- 需求:在A应用的一个Activity中包含了WebView,WebView加载的是第三方的应用的数据,想要在该WebView页面打开第三方应用B,即在WebView通过点击事件或者链接打开第三方应用B。
1.scheme协议定义和用途及需求的实现思路
1.Android中的scheme是一种页面内跳转协议,是一种非常好的实现机制;
2.通过定义自己的scheme协议,可以非常方便的跳转app中的各个页面;
3.在h5页面定义链接,跳转到指定的activity页面。客户端向h5页面注册一个urlscheme,然后由scheme协议用于从浏览器启动该activity;
4.使用场景归纳:客户端根据服务端下发的url跳转到指定的页面;从h5页面跳转到相应的activity页面;app根据url跳转到另一个指定的app页面(大型的公司,通过热门的链接跳转到另一个app);
2.scheme在android中的使用位置
<application
//省略无关代码...>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />
</intent-filter>
</activity>
</application>
3.scheme 协议定义和 http 协议类似,都是标准的 URI 结构。
[scheme:][//host:port][path][?query][#fragment]
scheme : 协议名称 - 必须
host : 协议地址 - 必须
port : 协议的端口,可以不填
path : 协议路径,可用 / 连接多个
query : 携带的参数可用 & 连接多个
fragment : 锚点
4.demo实例
- 4.1.应用A的代码
//1.静态的h5页面代码,位置:/main/assets/test.html
<!DOCTYPE html>
<html lang="en">
<!-- window.location = params 或者 window.location.href = params 均可-->
<head>
<script language="javascript">
function startApp(params)
{
window.location.href = params
}
</script>
</head>
<body>
<input type="button" onclick="startApp('definedscheme://main.definedhost')" value="启动app"/>
</body>
//2.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
//3.MainActivity类
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.webview);
webView.loadUrl("file:///android_asset/test.html");
webView.getSettings().setJavaScriptEnabled(true);
//这里有一个注意事项,不能调用setWebViewClient方法,调用后会出现跳转不成功的情况,
//具体原因自己还没有弄清楚,有知道的小伙伴,望告知。
}
}
4.2.应用B的代码
//1.AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="app1"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- TODO 需要添加下面的intent-filter配置,要新写一个intent-filter,如果直接写在launcher打开的filter中则会app图标消失-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- TODO scheme 允许在浏览器中打开-->
<category android:name="android.intent.category.BROWSABLE" />
<!-- TODO scheme 相关信息配置-->
<data android:scheme="definedscheme" android:host="main.definedhost">
</data>
</intent-filter>
</activity>
</application>
//2.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:id="@+id/text"
android:text="这是被唤起的app页面"
android:layout_height="wrap_content" />
</LinearLayout>
//3.MainActivity类
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private String TAG = "TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
Log.e(TAG, "scheme:" + intent.getScheme());
Uri uri = intent.getData();
if (uri != null) {
// 获取 scheme 名称
Log.e(TAG, "scheme: " + uri.getScheme());
// 获取 scheme 的host
Log.e(TAG, "host: " + uri.getHost());
// 获取 scheme 的路径
Log.e(TAG, "path: " + uri.getPath());
// 获取 scheme 的参数,?后面的部分
Log.e(TAG, "queryString: " + uri.getQuery());
// 获取 scheme 中的 param 参数
Log.e(TAG, "queryParameter: " + uri.getQueryParameter("param"));
}
}
}
- 4.3.注意事项
步骤4.2,在AndroidManifest.xml文件中,MainActivity中要新写一个intent-filter,如果直接写在launcher打开的filter中则会app图标消失(因为category被覆盖为DEAFAULT)
- 4.4.其中的 intent 实例有下面的方法可以获取相应的 scheme 信息:
getScheme() :获取Uri中的scheme名称:[scheme:]
getSchemeSpecificPart() :获取Uri中的scheme-specific-part:部分:[//host:port][path]
getFragment() :获取Uri中的Fragment部分:[#fragment]
getAuthority() :获取Uri中Authority部分:[//host:port]
getPath() :获取Uri中path部分:[path]
getQuery() :获取Uri中的query部分:[?query]
getHost() :获取Authority中的Host字符串
getPost() :获取Authority中的Port字符串
List< String> getPathSegments() :依次提取出Path的各个部分的字符串,以字符串数组的形式输出
getQueryParameter(String key) :获取query部分中 key 对应的参数值
5.总结
- 在实际项目中加载的是具体的网页,若需要传递参数到第三方应用中,可以通过CookieManager对象写入需要传递的数据,然后在h5页面动态的传递参数,例如:将上面的静态页面中startApp(params)方法的形参params赋值为definedscheme://main.definedhost?canshu1=value1&canshu2=value2,则静态的h5页面变动的代码更改为:
<input type="button" onclick="startApp('definedscheme://main.definedhost?canshu1=value1&canshu2=value2')" value="启动app"/>
- 此时,在被唤醒的app中可以获取键为canshu1和canshu2所应用的值value1和value2,即传递过来的值。
- 最后总结:该文章介绍了在WebView中打开第三方应用的实现方式,且可以传递参数。如有不足之处,请大家多多指正!觉得有所帮助,请点个赞呗。