您的位置:首页 > 移动开发

关于使用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 加入判断 网上通用的方法

***纠正一处错误***
判断协议类型的时候,@纠错,此处的判断不应该为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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: