forked from organicmaps/organicmaps
[booking][ios][android] deep links into platforms
This commit is contained in:
parent
774e6930d8
commit
219b3c78f5
12 changed files with 149 additions and 65 deletions
|
@ -61,7 +61,7 @@ void PrepareClassRefs(JNIEnv * env, jclass sponsoredClass)
|
|||
// Sponsored(String rating, String price, String urlBook, String urlDescription)
|
||||
g_sponsoredClassConstructor = jni::GetConstructorID(
|
||||
env, g_sponsoredClass,
|
||||
"(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
|
||||
"(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;"
|
||||
"Ljava/lang/String;IILjava/lang/String;)V");
|
||||
// static void onPriceReceived(final String id, final String price, final String currency)
|
||||
g_priceCallback =
|
||||
|
@ -124,6 +124,7 @@ JNIEXPORT jobject JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_na
|
|||
static_cast<jint>(place_page::rating::GetImpress(ppInfo.GetRatingRawValue())),
|
||||
jni::ToJavaString(env, ppInfo.GetApproximatePricing()),
|
||||
jni::ToJavaString(env, ppInfo.GetSponsoredUrl()),
|
||||
jni::ToJavaString(env, ppInfo.GetSponsoredDeepLink()),
|
||||
jni::ToJavaString(env, ppInfo.GetSponsoredDescriptionUrl()),
|
||||
jni::ToJavaString(env, ppInfo.GetSponsoredReviewUrl()),
|
||||
static_cast<jint>(ppInfo.GetSponsoredType()),
|
||||
|
|
|
@ -46,7 +46,7 @@ void PrepareClassRefs(JNIEnv * env)
|
|||
"(I[Lcom/mapswithme/maps/taxi/TaxiInfo$Product;)V");
|
||||
g_taxiInfoErrorConstructor = jni::GetConstructorID(env, g_taxiInfoErrorClass,
|
||||
"(ILjava/lang/String;)V");
|
||||
g_taxiLinksClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/taxi/TaxiLinks");
|
||||
g_taxiLinksClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/util/SponsoredLinks");
|
||||
g_taxiLinksConstructor =
|
||||
jni::GetConstructorID(env, g_taxiLinksClass, "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.mapswithme.maps.bookmarks.data.MapObject;
|
|||
import com.mapswithme.maps.location.LocationHelper;
|
||||
import com.mapswithme.maps.taxi.TaxiAdapter;
|
||||
import com.mapswithme.maps.taxi.TaxiInfo;
|
||||
import com.mapswithme.maps.taxi.TaxiLinks;
|
||||
import com.mapswithme.util.SponsoredLinks;
|
||||
import com.mapswithme.maps.taxi.TaxiManager;
|
||||
import com.mapswithme.maps.widget.DotPager;
|
||||
import com.mapswithme.maps.widget.recycler.DotDividerItemDecoration;
|
||||
|
@ -252,7 +252,8 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
|||
{
|
||||
if (RoutingController.get().isTaxiRouterType() && mTaxiInfo != null)
|
||||
{
|
||||
mStart.setText(Utils.isTaxiAppInstalled(mContext, mTaxiInfo.getType())
|
||||
String packageName = TaxiManager.getTaxiPackageName(mTaxiInfo.getType());
|
||||
mStart.setText(Utils.isAppInstalled(mContext, packageName)
|
||||
? R.string.taxi_order : R.string.install_app);
|
||||
mStart.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
|
@ -291,16 +292,12 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
|||
if (mTaxiProduct == null || mTaxiInfo == null)
|
||||
return;
|
||||
|
||||
boolean isTaxiInstalled = Utils.isTaxiAppInstalled(mContext, mTaxiInfo.getType());
|
||||
MapObject startPoint = RoutingController.get().getStartPoint();
|
||||
MapObject endPoint = RoutingController.get().getEndPoint();
|
||||
TaxiLinks links = TaxiManager.getTaxiLink(mTaxiProduct.getProductId(), mTaxiInfo.getType(),
|
||||
startPoint, endPoint);
|
||||
SponsoredLinks links = TaxiManager.getTaxiLink(mTaxiProduct.getProductId(), mTaxiInfo.getType(),
|
||||
startPoint, endPoint);
|
||||
if (links != null)
|
||||
{
|
||||
Utils.launchTaxiApp(mContext, links, mTaxiInfo.getType());
|
||||
trackTaxiStatistics(mTaxiInfo.getType(), isTaxiInstalled);
|
||||
}
|
||||
launchTaxiApp(links);
|
||||
}
|
||||
|
||||
void showError(@StringRes int message)
|
||||
|
@ -426,4 +423,27 @@ final class RoutingBottomMenuController implements View.OnClickListener
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void launchTaxiApp(@Nullable SponsoredLinks links)
|
||||
{
|
||||
String packageName = TaxiManager.getTaxiPackageName(mTaxiInfo.getType());
|
||||
boolean isTaxiInstalled = Utils.isAppInstalled(mContext, packageName);
|
||||
Utils.PartnerAppOpenMode openMode = Utils.PartnerAppOpenMode.None;
|
||||
|
||||
switch (mTaxiInfo.getType())
|
||||
{
|
||||
case TaxiManager.PROVIDER_UBER:
|
||||
openMode = Utils.PartnerAppOpenMode.Direct;
|
||||
break;
|
||||
case TaxiManager.PROVIDER_YANDEX:
|
||||
openMode = Utils.PartnerAppOpenMode.Indirect;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unsupported taxi type: " + mTaxiInfo.getType());
|
||||
}
|
||||
|
||||
Utils.openPartner(mContext, links, packageName, openMode);
|
||||
|
||||
trackTaxiStatistics(mTaxiInfo.getType(), isTaxiInstalled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.support.annotation.Nullable;
|
|||
|
||||
import com.mapswithme.maps.bookmarks.data.MapObject;
|
||||
import com.mapswithme.util.NetworkPolicy;
|
||||
import com.mapswithme.util.SponsoredLinks;
|
||||
import com.mapswithme.util.concurrency.UiThread;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
@ -84,8 +85,8 @@ public class TaxiManager
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public static TaxiLinks getTaxiLink(@NonNull String productId, @TaxiType int type,
|
||||
@Nullable MapObject startPoint, @Nullable MapObject endPoint)
|
||||
public static SponsoredLinks getTaxiLink(@NonNull String productId, @TaxiType int type,
|
||||
@Nullable MapObject startPoint, @Nullable MapObject endPoint)
|
||||
{
|
||||
if (startPoint == null || endPoint == null)
|
||||
return null;
|
||||
|
@ -96,6 +97,20 @@ public class TaxiManager
|
|||
endPoint.getLon());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getTaxiPackageName(@TaxiManager.TaxiType int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TaxiManager.PROVIDER_UBER:
|
||||
return "com.ubercab";
|
||||
case TaxiManager.PROVIDER_YANDEX:
|
||||
return "ru.yandex.taxi";
|
||||
default:
|
||||
throw new AssertionError("Unsupported taxi type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTaxiListener(@Nullable TaxiListener listener)
|
||||
{
|
||||
mListener = listener;
|
||||
|
@ -105,9 +120,9 @@ public class TaxiManager
|
|||
double srcLon, double dstLat, double dstLon);
|
||||
|
||||
@NonNull
|
||||
public native TaxiLinks nativeGetTaxiLinks(@NonNull NetworkPolicy policy, @TaxiType int type,
|
||||
@NonNull String productId, double srcLon,
|
||||
double srcLat, double dstLat, double dstLon);
|
||||
public native SponsoredLinks nativeGetTaxiLinks(@NonNull NetworkPolicy policy, @TaxiType int type,
|
||||
@NonNull String productId, double srcLon,
|
||||
double srcLat, double dstLat, double dstLon);
|
||||
|
||||
public enum ErrorCode
|
||||
{
|
||||
|
|
|
@ -84,6 +84,7 @@ import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
|
|||
import com.mapswithme.util.ConnectionState;
|
||||
import com.mapswithme.util.Graphics;
|
||||
import com.mapswithme.util.NetworkPolicy;
|
||||
import com.mapswithme.util.SponsoredLinks;
|
||||
import com.mapswithme.util.StringUtils;
|
||||
import com.mapswithme.util.ThemeUtils;
|
||||
import com.mapswithme.util.UiUtils;
|
||||
|
@ -941,6 +942,8 @@ public class PlacePageView extends RelativeLayout
|
|||
if (info == null)
|
||||
return;
|
||||
|
||||
Utils.PartnerAppOpenMode partnerAppOpenMode = Utils.PartnerAppOpenMode.None;
|
||||
|
||||
switch (info.getType())
|
||||
{
|
||||
case Sponsored.TYPE_BOOKING:
|
||||
|
@ -949,6 +952,7 @@ public class PlacePageView extends RelativeLayout
|
|||
|
||||
if (book)
|
||||
{
|
||||
partnerAppOpenMode = Utils.PartnerAppOpenMode.Direct;
|
||||
Statistics.INSTANCE.trackBookHotelEvent(info, mMapObject);
|
||||
}
|
||||
else
|
||||
|
@ -971,7 +975,17 @@ public class PlacePageView extends RelativeLayout
|
|||
|
||||
try
|
||||
{
|
||||
Utils.openUrl(getContext(), book ? info.getUrl() : info.getDescriptionUrl());
|
||||
if (partnerAppOpenMode != Utils.PartnerAppOpenMode.None)
|
||||
{
|
||||
SponsoredLinks links = new SponsoredLinks(info.getDeepLink(), info.getUrl());
|
||||
String packageName = Sponsored.GetPackageName(info.getType());
|
||||
|
||||
Utils.openPartner(getContext(), links, packageName, partnerAppOpenMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.openUrl(getContext(), book ? info.getUrl() : info.getDescriptionUrl());
|
||||
}
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
|
|
|
@ -201,6 +201,8 @@ public final class Sponsored
|
|||
@NonNull
|
||||
private final String mUrl;
|
||||
@NonNull
|
||||
private final String mDeepLink;
|
||||
@NonNull
|
||||
private final String mDescriptionUrl;
|
||||
@NonNull
|
||||
private final String mReviewUrl;
|
||||
|
@ -210,14 +212,16 @@ public final class Sponsored
|
|||
@NonNull
|
||||
private final String mPartnerName;
|
||||
|
||||
public Sponsored(@NonNull String rating, @UGC.Impress int impress, @NonNull String price,
|
||||
@NonNull String url, @NonNull String descriptionUrl, @NonNull String reviewUrl,
|
||||
@SponsoredType int type, int partnerIndex, @NonNull String partnerName)
|
||||
private Sponsored(@NonNull String rating, @UGC.Impress int impress, @NonNull String price,
|
||||
@NonNull String url, @NonNull String deepLink, @NonNull String descriptionUrl,
|
||||
@NonNull String reviewUrl, @SponsoredType int type, int partnerIndex,
|
||||
@NonNull String partnerName)
|
||||
{
|
||||
mRating = rating;
|
||||
mImpress = impress;
|
||||
mPrice = price;
|
||||
mUrl = url;
|
||||
mDeepLink = deepLink;
|
||||
mDescriptionUrl = descriptionUrl;
|
||||
mReviewUrl = reviewUrl;
|
||||
mType = type;
|
||||
|
@ -260,6 +264,12 @@ public final class Sponsored
|
|||
return mUrl;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getDeepLink()
|
||||
{
|
||||
return mDeepLink;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
String getDescriptionUrl()
|
||||
{
|
||||
|
@ -379,6 +389,18 @@ public final class Sponsored
|
|||
listener.onHotelInfoReceived(id, info);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String GetPackageName(@SponsoredType int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Sponsored.TYPE_BOOKING:
|
||||
return "com.booking";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static native Sponsored nativeGetCurrent();
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package com.mapswithme.maps.taxi;
|
||||
package com.mapswithme.util;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class TaxiLinks
|
||||
public class SponsoredLinks
|
||||
{
|
||||
@NonNull
|
||||
private final String mDeepLink;
|
||||
@NonNull
|
||||
private final String mUniversalLink;
|
||||
|
||||
public TaxiLinks(@NonNull String deepLink, @NonNull String universalLink)
|
||||
public SponsoredLinks(@NonNull String deepLink, @NonNull String universalLink)
|
||||
{
|
||||
mDeepLink = deepLink;
|
||||
mUniversalLink = universalLink;
|
|
@ -32,7 +32,6 @@ import com.mapswithme.maps.BuildConfig;
|
|||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.maps.activity.CustomNavigateUpListener;
|
||||
import com.mapswithme.maps.taxi.TaxiLinks;
|
||||
import com.mapswithme.maps.taxi.TaxiManager;
|
||||
import com.mapswithme.util.concurrency.UiThread;
|
||||
import com.mapswithme.util.log.Logger;
|
||||
|
@ -304,7 +303,7 @@ public class Utils
|
|||
return installationId;
|
||||
}
|
||||
|
||||
private static boolean isAppInstalled(@NonNull Activity context, @NonNull String packageName)
|
||||
public static boolean isAppInstalled(@NonNull Context context, @NonNull String packageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -317,57 +316,47 @@ public class Utils
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isTaxiAppInstalled(@NonNull Activity context, @TaxiManager.TaxiType int type)
|
||||
public static void launchAppDirect(@NonNull Context context, @NonNull SponsoredLinks links,
|
||||
String packageName)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TaxiManager.PROVIDER_UBER:
|
||||
return Utils.isAppInstalled(context, "com.ubercab");
|
||||
case TaxiManager.PROVIDER_YANDEX:
|
||||
return Utils.isAppInstalled(context, "ru.yandex.taxi");
|
||||
default:
|
||||
throw new AssertionError("Unsupported taxi type: " + type);
|
||||
}
|
||||
}
|
||||
boolean isAppInstalled = Utils.isAppInstalled(context, packageName);
|
||||
|
||||
public static void launchTaxiApp(@NonNull Activity context, @NonNull TaxiLinks links,
|
||||
@TaxiManager.TaxiType int type)
|
||||
{
|
||||
switch (type)
|
||||
if (!isAppInstalled)
|
||||
{
|
||||
case TaxiManager.PROVIDER_UBER:
|
||||
launchUber(context, links, isTaxiAppInstalled(context, type));
|
||||
break;
|
||||
case TaxiManager.PROVIDER_YANDEX:
|
||||
launchYandexTaxi(context, links);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unsupported taxi type: " + type);
|
||||
openUrl(context, links.getUniversalLink());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void launchUber(@NonNull Activity context, @NonNull TaxiLinks links, boolean isAppInstalled)
|
||||
{
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
if (isAppInstalled)
|
||||
{
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setData(Uri.parse(links.getDeepLink()));
|
||||
} else
|
||||
{
|
||||
// No Taxi app! Open mobile website.
|
||||
intent.setData(Uri.parse(links.getUniversalLink()));
|
||||
}
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setData(Uri.parse(links.getDeepLink()));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
private static void launchYandexTaxi(@NonNull Activity context, @NonNull TaxiLinks links)
|
||||
public static void launchAppIndirect(@NonNull Context context, @NonNull SponsoredLinks links)
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(links.getDeepLink()));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void openPartner(@NonNull Context activity, @NonNull SponsoredLinks links,
|
||||
@NonNull String packageName, @NonNull PartnerAppOpenMode openMode)
|
||||
{
|
||||
switch (openMode)
|
||||
{
|
||||
case Direct:
|
||||
launchAppDirect(activity, links, packageName);
|
||||
break;
|
||||
case Indirect:
|
||||
launchAppIndirect(activity, links);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unsupported partner app open mode: " + openMode +
|
||||
"; Package name: " + packageName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendTo(@NonNull Context context, @NonNull String email)
|
||||
{
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||
|
@ -562,4 +551,9 @@ public class Utils
|
|||
|
||||
return Character.toLowerCase(src.charAt(0)) + src.substring(1);
|
||||
}
|
||||
|
||||
public enum PartnerAppOpenMode
|
||||
{
|
||||
None, Direct, Indirect
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
<string>uber</string>
|
||||
<string>yandextaxi</string>
|
||||
<string>tel</string>
|
||||
<string>booking</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
|
|
|
@ -250,6 +250,7 @@ using NewSectionsAreReady = void (^)(NSRange const & range, MWMPlacePageData * d
|
|||
- (BOOL)isMyPosition;
|
||||
- (BOOL)isRoutePoint;
|
||||
- (BOOL)isPreviewExtended;
|
||||
- (BOOL)isPartnerAppInstalled;
|
||||
|
||||
+ (MWMRatingSummaryViewValueType)ratingValueType:(place_page::rating::Impress)impress;
|
||||
|
||||
|
|
|
@ -519,10 +519,12 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
|
|||
- (NSString *)bookingApproximatePricing { return self.isBooking ? @(m_info.GetApproximatePricing().c_str()) : nil; }
|
||||
- (NSURL *)sponsoredURL
|
||||
{
|
||||
// There are sponsors without URL. For such psrtners we do not show special button.
|
||||
if (m_info.IsSponsored() && !m_info.GetSponsoredUrl().empty())
|
||||
auto const link = self.isPartnerAppInstalled ? m_info.GetSponsoredDeepLink() : m_info.GetSponsoredUrl();
|
||||
|
||||
// There are sponsors without URL. For such partners we do not show special button.
|
||||
if (m_info.IsSponsored() && !link.empty())
|
||||
{
|
||||
auto urlString = [@(m_info.GetSponsoredUrl().c_str())
|
||||
auto urlString = [@(link.c_str())
|
||||
stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet
|
||||
.URLQueryAllowedCharacterSet];
|
||||
auto url = [NSURL URLWithString:urlString];
|
||||
|
@ -788,6 +790,16 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
|
|||
- (BOOL)isHTMLDescription { return strings::IsHTML(m_info.GetBookmarkData().GetDescription()); }
|
||||
- (BOOL)isRoutePoint { return m_info.IsRoutePoint(); }
|
||||
- (BOOL)isPreviewExtended { return m_info.IsPreviewExtended(); }
|
||||
- (BOOL)isPartnerAppInstalled
|
||||
{
|
||||
NSURL * url;
|
||||
switch (m_info.GetSponsoredType())
|
||||
{
|
||||
case SponsoredType::Booking: url = [NSURL URLWithString:@"booking://"]; break;
|
||||
default: return NO;
|
||||
}
|
||||
return [UIApplication.sharedApplication canOpenURL:url];
|
||||
}
|
||||
|
||||
+ (MWMRatingSummaryViewValueType)ratingValueType:(rating::Impress)impress
|
||||
{
|
||||
|
|
|
@ -484,7 +484,11 @@ void logSponsoredEvent(MWMPlacePageData * data, NSString * eventName)
|
|||
logSponsoredEvent(data, eventName);
|
||||
NSURL * url = isDescription ? data.sponsoredDescriptionURL : data.sponsoredURL;
|
||||
NSAssert(url, @"Sponsored url can't be nil!");
|
||||
[self.ownerViewController openUrl:url];
|
||||
|
||||
if (data.isPartnerAppInstalled)
|
||||
[UIApplication.sharedApplication openURL:url];
|
||||
else
|
||||
[self.ownerViewController openUrl:url];
|
||||
}
|
||||
|
||||
- (void)searchBookingHotels
|
||||
|
|
Loading…
Add table
Reference in a new issue