[booking][ios][android] deep links into platforms

This commit is contained in:
Arsentiy Milchakov 2018-02-06 19:04:33 +03:00 committed by Aleksandr Zatsepin
parent 774e6930d8
commit 219b3c78f5
12 changed files with 149 additions and 65 deletions

View file

@ -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()),

View file

@ -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");
}

View file

@ -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);
}
}

View file

@ -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
{

View file

@ -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)
{

View file

@ -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();

View file

@ -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;

View file

@ -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
}
}

View file

@ -108,6 +108,7 @@
<string>uber</string>
<string>yandextaxi</string>
<string>tel</string>
<string>booking</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>

View file

@ -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;

View file

@ -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
{

View file

@ -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