关于使用Intent协议在webview中跳转三方app
2017-10-25 18:06
1486 查看
最近项目上有个需求,是关于在webview加载一个url的形式使用Intent协议跳转到指定的app页面,查看Intent源码发现Intent.parseUri()方法的第二个参数flag有三种类型: Intent.URI_ANDROID_APP_SCHEME 和 Intent.URI_INTENT_SCHEME 还有 URI_ALLOW_UNSAFE ;第三种不安全,一般不使用。 前俩种的格式为intent://host/#Intent;scheme=hansel;package=com.hansel.app;end 在#Intent之前可以带一些参数
android-app://{package_id}[/{scheme}[/{host}[/{path}]]][#Intent;{…}] 这个是第二种(PS:这种的scheme总是android-app)
在接收的app的manifest中的Activity注册这些信息
(intent://协议默认的是Action_View ; app-android 默认在格式中只指定了包名的话,actionMain ,如果有scheme和host则默认为actionView,当然如果协议中指定了action的话,就是你指定的action,下面是官方的截图)
接收的app注册这些信息,这里MainActivity 是接收intent:// 协议 Main2Activity接收android-app:// 协议。使用intent://时候一定要注册data的scheme 用来和发起请求的scheme匹配对应; 但是android-app则不太一样,可以不注册data的scheme,但是请求的时候要指定component即:”android-app://com.ebensz.appmanager/#Intent;component=com.ebensz.appmanager/com.ebensz.appmanager.MainActivity;end”; 而且android-app时候接收到的scheme 是android-app; intent://则是指定的scheme
发起请求的代码:在shouldoverride 加入判断 网上通用的方法
附上android文档的解释
/**
* Flag for use with {@link #toUri} and {@link #parseUri}: the URI string
* always has the “intent:” scheme. This syntax can be used when you want
* to later disambiguate between URIs that are intended to describe an
* Intent vs. all others that should be treated as raw URIs. When used
* with {@link #parseUri}, any other scheme will result in a generic
* VIEW action for that raw URI.
*/
public static final int URI_INTENT_SCHEME = 1<<0;
Intent.parseUri() 解读:
android-app://{package_id}[/{scheme}[/{host}[/{path}]]][#Intent;{…}] 这个是第二种(PS:这种的scheme总是android-app)
在接收的app的manifest中的Activity注册这些信息
(intent://协议默认的是Action_View ; app-android 默认在格式中只指定了包名的话,actionMain ,如果有scheme和host则默认为actionView,当然如果协议中指定了action的话,就是你指定的action,下面是官方的截图)
接收的app注册这些信息,这里MainActivity 是接收intent:// 协议 Main2Activity接收android-app:// 协议。使用intent://时候一定要注册data的scheme 用来和发起请求的scheme匹配对应; 但是android-app则不太一样,可以不注册data的scheme,但是请求的时候要指定component即:”android-app://com.ebensz.appmanager/#Intent;component=com.ebensz.appmanager/com.ebensz.appmanager.MainActivity;end”; 而且android-app时候接收到的scheme 是android-app; intent://则是指定的scheme
发起请求的代码:在shouldoverride 加入判断 网上通用的方法
***纠正一处错误*** 判断协议类型的时候,@纠错,此处的判断不应该为else if (url.startWith("intent")),这样的话不能响应自定义的协议头(大部分的app是使用自己定义的scheme头,把自定义的类型并入flag是URI_INTENT_SCHEME),现在贴下原因: (太长了就放在最后了哈) Intent intent = null; // perform generic parsing of the URI to turn it into an Intent. try { if (url.startsWith("android-app://")){ intent = Intent.parseUri(url,Intent.URI_ANDROID_APP_SCHEME); }else { // @纠错 intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); } } catch (URISyntaxException ex) { LogUtil.w("Browser", "Bad URI " + url + ": " + ex.getMessage()); return false; } if (intent!=null && !TextUtils.isEmpty(intent.getScheme()) && BrowserUtils.isBlackScheme(intent.getScheme())) { return true; } // check whether the intent can be resolved. If not, we will see // whether we can download it from the Market. // 如果本地没装能响应特殊协议的应用则return if (getPackageManager().resolveActivity(intent, 0) == null) { return true; } // sanitize the Intent, ensuring web pages can not bypass browser // security (only access to BROWSABLE activities). intent.addCategory(Intent.CATEGORY_BROWSABLE); if (!url.startsWith("android-app://")) { intent.setComponent(null); } try { if (startActivityIfNeeded(intent, -1)) { LogUtil.d("tag","sucess use the intent "); return true; } } catch (ActivityNotFoundException ex) { LogUtil.d("tag","error message is --> " + ex.getMessage()); // ignore the error. If no application can handle the URL, // eg about:blank, assume the browser can handle it. } catch (SecurityException se) { se.printStackTrace(); }
附上android文档的解释
/**
* Flag for use with {@link #toUri} and {@link #parseUri}: the URI string
* always has the “intent:” scheme. This syntax can be used when you want
* to later disambiguate between URIs that are intended to describe an
* Intent vs. all others that should be treated as raw URIs. When used
* with {@link #parseUri}, any other scheme will result in a generic
* VIEW action for that raw URI.
*/
public static final int URI_INTENT_SCHEME = 1<<0;
/** * Flag for use with {@link #toUri} and {@link #parseUri}: the URI string * always has the "android-app:" scheme. This is a variation of * {@link #URI_INTENT_SCHEME} whose format is simpler for the case of an * http/https URI being delivered to a specific package name. The format * is: * * <pre class="prettyprint"> * android-app://{package_id}[/{scheme}[/{host}[/{path}]]][#Intent;{...}]</pre> * * <p>In this scheme, only the <code>package_id</code> is required. If you include a host, * you must also include a scheme; including a path also requires both a host and a scheme. * The final #Intent; fragment can be used without a scheme, host, or path. * Note that this can not be * used with intents that have a {@link #setSelector}, since the base intent * will always have an explicit package name.</p> * * <p>Some examples of how this scheme maps to Intent objects:</p> * <table border="2" width="85%" align="center" frame="hsides" rules="rows"> * <colgroup align="left" /> * <colgroup align="left" /> * <thead> * <tr><th>URI</th> <th>Intent</th></tr> * </thead> * * <tbody> * <tr><td><code>android-app://com.example.app</code></td> * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0"> * <tr><td>Action: </td><td>{@link #ACTION_MAIN}</td></tr> * <tr><td>Package: </td><td><code>com.example.app</code></td></tr> * </table></td> * </tr> * <tr><td><code>android-app://com.example.app/http/example.com</code></td> * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0"> * <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr> * <tr><td>Data: </td><td><code>http://example.com/</code></td></tr> * <tr><td>Package: </td><td><code>com.example.app</code&g 4000 t;</td></tr> * </table></td> * </tr> * <tr><td><code>android-app://com.example.app/http/example.com/foo?1234</code></td> * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0"> * <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr> * <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr> * <tr><td>Package: </td><td><code>com.example.app</code></td></tr> * </table></td> * </tr> * <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;end</code></td> * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0"> * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr> * <tr><td>Package: </td><td><code>com.example.app</code></td></tr> * </table></td> * </tr> * <tr><td><code>android-app://com.example.app/http/example.com/foo?1234<br />#Intent;action=com.example.MY_ACTION;end</code></td> * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0"> * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr> * <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr> * <tr><td>Package: </td><td><code>com.example.app</code></td></tr> * </table></td> * </tr> * <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;<br />i.some_int=100;S.some_str=hello;end</code></td> * <td><table border="" style="margin:0" > * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr> * <tr><td>Package: </td><td><code>com.example.app</code></td></tr> * <tr><td>Extras: </td><td><code>some_int=(int)100<br />some_str=(String)hello</code></td></tr> * </table></td> * </tr> * </tbody> * </table> */ public static final int URI_ANDROID_APP_SCHEME = 1<<1;
Intent.parseUri() 解读:
/** * Create an intent from a URI. This URI may encode the action, * category, and other intent fields, if it was returned by * {@link #toUri}. If the Intent was not generate by toUri(), its data * will be the entire URI and its action will be ACTION_VIEW. * * <p>The URI given here must not be relative -- that is, it must include * the scheme and full path. * * @param uri The URI to turn into an Intent. * @param flags Additional processing flags. Either 0, * {@link #URI_INTENT_SCHEME}, or {@link #URI_ANDROID_APP_SCHEME}. * * @return Intent The newly created Intent object. * * @throws URISyntaxException Throws URISyntaxError if the basic URI syntax * it bad (as parsed by the Uri class) or the Intent data within the * URI is invalid. * * @see #toUri */ public static Intent parseUri(String uri, int flags) throws URISyntaxException { int i = 0; try { final boolean androidApp = uri.startsWith("android-app:"); // flag传入URI_INTENT_SCHEME这个条件成立,生成的是自定义的scheme协议,非intent://和app-android://,所以上面把自定义的scheme加入URI_INTENT_SCHEME即可 if ((flags&(URI_INTENT_SCHEME|URI_ANDROID_APP_SCHEME)) != 0) { if (!uri.startsWith("intent:") && !androidApp) { Intent intent = new Intent(ACTION_VIEW); try { intent.setData(Uri.parse(uri)); } catch (IllegalArgumentException e) { throw new URISyntaxException(uri, e.getMessage()); } return intent; } } // 看下是否有#Intent后续的参数内容 i = uri.lastIndexOf("#"); // simple case if (i == -1) { if (!androidApp) { return new Intent(ACTION_VIEW, Uri.parse(uri)); } // old format Intent URI } else if (!uri.startsWith("#Intent;", i)) { if (!androidApp) { return getIntentOld(uri, flags); } else { i = -1; } } // new format Intent intent = new Intent(ACTION_VIEW); Intent baseIntent = intent; boolean explicitAction = false;// 指定action boolean inSelector = false; // fetch data part, if present String scheme = null; String data; if (i >= 0) { data = uri.substring(0, i); i += 8; // length of "#Intent;" } else { data = uri; } // 获取#Intent后面的附加属性 // loop over contents of Intent, all name=value; while (i >= 0 && !uri.startsWith("end", i)) { int eq = uri.indexOf('=', i); if (eq < 0) eq = i-1; int semi = uri.indexOf(';', i); String value = eq < semi ? Uri.decode(uri.substring(eq + 1, semi)) : ""; // action if (uri.startsWith("action=", i)) { intent.setAction(value); if (!inSelector) { explicitAction = true; } } // categories else if (uri.startsWith("category=", i)) { intent.addCategory(value); } // type else if (uri.startsWith("type=", i)) { intent.mType = value; } // launch flags else if (uri.startsWith("launchFlags=", i)) { intent.mFlags = Integer.decode(value).intValue(); if ((flags& URI_ALLOW_UNSAFE) == 0) { intent.mFlags &= ~IMMUTABLE_FLAGS; } } // package else if (uri.startsWith("package=", i)) { intent.mPackage = value; } // component else if (uri.startsWith("component=", i)) { intent.mComponent = ComponentName.unflattenFromString(value); } // scheme else if (uri.startsWith("scheme=", i)) { if (inSelector) { intent.mData = Uri.parse(value + ":"); } else { scheme = value; } } // source bounds else if (uri.startsWith("sourceBounds=", i)) { intent.mSourceBounds = Rect.unflattenFromString(value); } // selector else if (semi == (i+3) && uri.startsWith("SEL", i)) { intent = new Intent(); inSelector = true; } // extra else { String key = Uri.decode(uri.substring(i + 2, eq)); // create Bundle if it doesn't already exist if (intent.mExtras == null) intent.mExtras = new Bundle(); Bundle b = intent.mExtras; // add EXTRA if (uri.startsWith("S.", i)) b.putString(key, value); else if (uri.startsWith("B.", i)) b.putBoolean(key, Boolean.parseBoolean(value)); else if (uri.startsWith("b.", i)) b.putByte(key, Byte.parseByte(value)); else if (uri.startsWith("c.", i)) b.putChar(key, value.charAt(0)); else if (uri.startsWith("d.", i)) b.putDouble(key, Double.parseDouble(value)); else if (uri.startsWith("f.", i)) b.putFloat(key, Float.parseFloat(value)); else if (uri.startsWith("i.", i)) b.putInt(key, Integer.parseInt(value)); else if (uri.startsWith("l.", i)) b.putLong(key, Long.parseLong(value)); else if (uri.startsWith("s.", i)) b.putShort(key, Short.parseShort(value)); else throw new URISyntaxException(uri, "unknown EXTRA type", i); } // move to the next item i = semi + 1; } if (inSelector) { // The Intent had a selector; fix it up. if (baseIntent.mPackage == null) { baseIntent.setSelector(intent); } intent = baseIntent; } if (data != null) { if (data.startsWith("intent:")) { data = data.substring(7); if (scheme != null) { data = scheme + ':' + data; } } else if (data.startsWith("android-app:")) { if (data.charAt(12) == '/' && data.charAt(13) == '/') { // Correctly formed android-app, first part is package name. int end = data.indexOf('/', 14); if (end < 0) { // All we have is a package name. intent.mPackage = data.substring(14); if (!explicitAction) {//没有action属性的时候“app-android”使用默认action_main intent.setAction(ACTION_MAIN); } data = ""; } else { // Target the Intent at the given package name always. String authority = null; intent.mPackage = data.substring(14, end); int newEnd; if ((end+1) < data.length()) { if ((newEnd=data.indexOf('/', end+1)) >= 0) { // Found a scheme, remember it. scheme = data.substring(end+1, newEnd); end = newEnd; if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) { // Found a authority, remember it. authority = data.substring(end+1, newEnd); end = newEnd; } } else { // All we have is a scheme. scheme = data.substring(end+1); } } if (scheme == null) { // If there was no scheme, then this just targets the package. if (!explicitAction) { intent.setAction(ACTION_MAIN); } data = ""; } else if (authority == null) { data = scheme + ":"; } else { data = scheme + "://" + authority + data.substring(end); } } } else { data = ""; } } if (data.length() > 0) { try { intent.mData = Uri.parse(data); } catch (IllegalArgumentException e) { throw new URISyntaxException(uri, e.getMessage()); } } } return intent; } catch (IndexOutOfBoundsException e) { throw new URISyntaxException(uri, "illegal Intent URI format", i); } }
相关文章推荐
- 关于Android7.0系统使用webview遇到的一个问题(二级跳转后界面空白)
- intent://platformapi/startapp?--Webview内跳转到支付宝网页
- 关于android webview 端调原生app 的支付宝接口实现 还有BeeCloud(秒支付) 的接入使用
- 关于iOS加载webView通过webView跳转回app
- 不使用webview,用手机浏览器的android app
- Fragment中使用ViewFlipper在严格模式下抛出android.app.IntentReceiverLeaked
- Android使用WebView嵌入网页,网页内点击跳转到另一个网页后,返回问题解决
- Android中关于WebView的使用办法
- 安卓开发_关于WebView使用链接时调用浏览器显示的问题
- 在当前的webview中跳转到新的url 使用WebView组件显示网页
- Android webview app 直接使用注入 javascript 解决中文输入问题
- Android KitKat 4.4 使用Chrome DevTools 进行WebView远程调试 | remote debug web APP in chrome
- 关于android 中WebView使用Css
- Andriod使用webview控件往APP里内嵌网页
- 不使用webview,用手机浏览器的android app
- webview使用sslError解决https跳转报错的问题
- 关于安全的建议:对投入使用的 XML Web Services 禁用 HTTP-GET 和 HTTP-POST 协议
- Andriod使用webview控件往APP里内嵌网页
- webview使用sslError解决https跳转报错的问题