最近项目上有个需求,是关于在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 加入判断 网上通用的方法
***纠正一处错误***
判断协议类型的时候,@纠错,此处的判断不应该为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&g