Android WebView 跳转第三方App
来源:互联网 发布:网上商城java源码 编辑:程序博客网 时间:2024/05/27 19:26
Android的WebView自身是支持网页挑起第三方App的,但是如果为WebView设置了自定义的WebViewClient,这个功能就失效了,解决方案如下。
WebViewClient中有一个方法:shouldOverrideUrlLoading,这个方法的作用是让业务层可以根据url的值决定用什么方式来处理这个url。
/** * Give the host application a chance to take over the control when a new * url is about to be loaded in the current WebView. If WebViewClient is not * provided, by default WebView will ask Activity Manager to choose the * proper handler for the url. If WebViewClient is provided, return true * means the host application handles the url, while return false means the * current WebView handles the url. * This method is not called for requests using the POST "method". * * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @return True if the host application wants to leave the current WebView * and handle the url itself, otherwise return false. */ public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; }
如果没有为WebView设置WebViewClient,那么WebView就会让Activity Manager来决定如何处理这个url,如果设置了WebViewClient,就需要通过该方法的返回值通知WebView是否需要让它处理,如果需要自行处理,就可以在该方法中处理该url。
具体代码如下
public boolean shouldOverrideUrlLoading(WebView view, String url) { if (shouldOverrideUrlLoadingByApp(view, url)) { return true; } return super.shouldOverrideUrlLoading(view, url); } /** * 根据url的scheme处理跳转第三方app的业务 */ private boolean shouldOverrideUrlLoadingByApp(WebView view, String url) { if (url.startsWith("http") || url.startsWith("https") || url.startsWith("ftp")) { //不处理http, https, ftp的请求 return false; } Intent intent; try { intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); } catch (URISyntaxException e) { XLLog.e(TAG, "URISyntaxException: " + e.getLocalizedMessage()); return false; } intent.setComponent(null); try { getContext().startActivity(intent); } catch (ActivityNotFoundException e) { XLLog.e(TAG, "ActivityNotFoundException: " + e.getLocalizedMessage()); return false; } return true; }
遇到的问题
1. 未安装目标app,DeepLink链接处理失败,浏览器也不能处理,导致出现无法访问的界面;
如上面的解决方案,当设备上没有安装目标app时,startActivity()
方法会抛出ActivityNotFoundException
,shouldOverrideUrlLoading()
方法就会返回false,该url就会交给浏览器处理,浏览器肯定无法处理这种自定义scheme的协议,就会抛出NOT_SUPPORT_SCHEME
错误,导致网页出现无法加载的错误页面。解决方法是判断浏览器能处理哪些scheme,如果检测到该url是浏览器无法处理的,就不让浏览器处理了,那么自然就不会出现这个问题。
2. 未安装目标app,点击DeepLink链接,根据链接内容跳转至应用市场或者通过网页触发目标app的下载链接
例如: intent://dangdang://product//pid=23248697#Intent;scheme=dangdang://product//pid=23248697;package=com.dangdang.buy2;end
,该url通过Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
解析后,intent中会包含应用报名,那么就可以先通过mActivity.getPackageManager().resolveActivity(intent, 0) == null
判断设备中是否有app能处理这个url,如果没有,就根据包名跳转应用市场进行下载。当然站在产品的角度,是不希望无偿帮应用市场导量的,所以也可以不跳转应用市场。一般来说,如果网页中的deeplink有这种需求,在检测到设备中无法处理该url时,还会触发目前app的下载链接,这种方案在网页中的实现目前没有去了解,只是知道这样会回调WebView的DownloadListener,客户端可以在回调中处理目标app的下载操作。
以上两个问题的解决方案
public class ADIntentUtils { private static final String TAG = "IntentUtils"; /** * 系统可以处理的url正则 */ private static final Pattern ACCEPTED_URI_SCHEME = Pattern.compile("(?i)" + // switch on case insensitive matching '(' + // begin group for scheme "(?:http|https|ftp|file)://" + "|(?:inline|data|about|javascript):" + "|(?:.*:.*@)" + ')' + "(.*)"); private Activity mActivity = null; public ADIntentUtils(Activity activity) { this.mActivity = activity; } public boolean shouldOverrideUrlLoadingByApp(WebView view, String url) { return shouldOverrideUrlLoadingByAppInternal(view, url, true); } /** * 广告业务的特殊处理 * 根据url的scheme处理跳转第三方app的业务 * 如果应用程序可以处理该url,就不要让浏览器处理了,返回true; * 如果没有应用程序可以处理该url,先判断浏览器能否处理,如果浏览器也不能处理,直接返回false拦截该url,不要再让浏览器处理。 * 避免出现当deepLink无法调起目标app时,展示加载失败的界面。 * <p> * 某些含有deepLink链接的网页,当使用deepLink跳转目标app失败时,如果将该deepLinkUrl交给系统处理,系统处理不了,会导致加载失败; * 示例: * 网页Url:https://m.ctrip.com/webapp/hotel/hoteldetail/687592/checkin-1-7.html?allianceid=288562&sid=964106&sourceid=2504&sepopup=12 * deepLinkUrl:ctrip://wireless/InlandHotel?checkInDate=20170504&checkOutDate=20170505&hotelId=687592&allianceid=288562&sid=960124&sourceid=2504&ouid=Android_Singapore_687592 * * @param interceptExternalProtocol 是否拦截自定义的外部协议,true:拦截,无论如何都不让浏览器处理;false:不拦截,如何没有成功处理该协议,继续让浏览器处理 */ private boolean shouldOverrideUrlLoadingByAppInternal(WebView view, String url, boolean interceptExternalProtocol) { if (isAcceptedScheme(url)) return false; Intent intent; try { intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); } catch (URISyntaxException e) { Log.e(TAG, "URISyntaxException: " + e.getLocalizedMessage()); return interceptExternalProtocol; } intent.setComponent(null); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { intent.setSelector(null); } //intent://dangdang://product//pid=23248697#Intent;scheme=dangdang://product//pid=23248697;package=com.dangdang.buy2;end //该Intent无法被设备上的应用程序处理 if (mActivity.getPackageManager().resolveActivity(intent, 0) == null) { return tryHandleByMarket(intent) || interceptExternalProtocol; } try { mActivity.startActivity(intent); } catch (ActivityNotFoundException e) { Log.e(TAG, "ActivityNotFoundException: " + e.getLocalizedMessage()); return interceptExternalProtocol; } return true; } private boolean tryHandleByMarket(Intent intent) { String packagename = intent.getPackage(); if (packagename != null) { intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packagename)); try{ mActivity.startActivity(intent); } catch (ActivityNotFoundException e) { Log.e(TAG, "tryHandleByMarket ActivityNotFoundException: " + e.getLocalizedMessage()); return false; } return true; } else { return false; } } /** * 该url是否属于浏览器能处理的内部协议 */ private boolean isAcceptedScheme(String url) { //正则中忽略了大小写,保险起见,还是转成小写 String lowerCaseUrl = url.toLowerCase(); Matcher acceptedUrlSchemeMatcher = ACCEPTED_URI_SCHEME.matcher(lowerCaseUrl); if (acceptedUrlSchemeMatcher.matches()) { return true; } return false; }}
- Android WebView 跳转第三方App
- android webview 打不开第三方app
- Android跳转到第三方App
- 跳转第三方地图app
- Android 解决webview中下载第三方APP的问题
- 【Android】webview点击跳转APP
- React Native跳转第三方APP
- React Native, IOS跳转第三方APP
- 第三方键盘跳转宿主app
- Cordova插件之跳转第三方app
- Android调用第三方App
- Android调用第三方App
- Android 调用第三方app
- Android 启动第三方app
- android 第三方app截图
- Android中的webview调用第三方支付
- Android第三方应用或者原生app内跳转React native的某个页面
- Android 跳转到第三方应用
- datatable分页动态加载
- 【九度OJ】题目1087:约数的个数 解题报告
- Google Java Style 中文版
- DB2初学者学习
- Echarts海南地图过小解决方案
- Android WebView 跳转第三方App
- windows下面自动打包exe批处理
- vue.js获取数据库数据
- 营救
- 如何使 vlc 支持 fdk-aac 编码(windows平台
- jstl的fmt标签(格式标签)
- 设备模型三(潜谈sysfs)
- 0-1背包(DP经典问题)
- 编写地道的go代码