最近在一個技術(shù)公眾號里看見Scheme,由于之前沒有接觸過。觸及到了我的知識盲點,于是花了些功夫去了解這個協(xié)議。
URL Scheme 有什么用?使用場景
Scheme 用于從瀏覽器或其他應(yīng)用中啟動本應(yīng)用。也就是說要從其他應(yīng)用中跳轉(zhuǎn)本應(yīng)用的界面或者網(wǎng)頁跳轉(zhuǎn)本應(yīng)用打開特定的界面。
如何定義Scheme協(xié)議
首先我們來看看URL Scheme 的格式
客戶端自定義的 URL 作為從一個應(yīng)用調(diào)用另一個的基礎(chǔ),遵循 RFC 1808 (Relative Uniform Resource Locators) 標(biāo)準(zhǔn)。這跟我們常見的網(wǎng)頁內(nèi)容 URL 格式一樣。
一個普通的 URL 分為幾個部分,scheme、host、port、relativePath、query、fragment(定義一個url包含了你定義的scheme,主機(jī)名或者域名,端口(可選)路徑,查詢條件等)
URL的一般語法格式為:
(帶方括號[]的為可選項):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
protocol: 協(xié)議也就是你定義的scheme
hostname: 地址域
port:端口
path:路徑
params:參數(shù)
在Android中的用法
在AndroidManifest.xml中定義intent-filter,這里我給出部分代碼
<activity
android:name=".SchemeTargetActivity"
android:launchMode="singleTask">
<!-- 要想在別的App上能成功調(diào)起App,必須添加intent過濾器 -->
<intent-filter>
<!-- 協(xié)議部分 可以隨便設(shè)置 還可以加一些host port path 等,協(xié)議規(guī)則越詳細(xì)定位界面更精確,-->
<!--<data android:scheme="bruce"></data>-->
<data android:scheme="bruce"
android:host="baidu"
android:port="8080"
android:path="/tieba"
></data>
<!-- 必須設(shè)置 -->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 如果需要外部網(wǎng)頁打開本頁面,還需要設(shè)置這個 -->
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
為什么設(shè)置singleTask就是為了防止生成多個實例多次啟動這個頁面。如果有傳參,我們可以重寫onNewIntent獲取參數(shù)
下面我給出兩個activity的代碼,注意這里兩個activity來自不同的應(yīng)用。我姑且定為C應(yīng)用,D應(yīng)用。 C調(diào)用D
C應(yīng)用的activity代碼
/**
* DATE:2018/3/21
* USER: liuzj
* DESC:
* email:liuzj@hi-board.com
*/
public class BActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
}
public void scheme(View view) {
if (hasApplication()) {
Toast.makeText(this, "有目標(biāo)界面", Toast.LENGTH_SHORT).show();
Uri uri = Uri.parse("bruce://baidu:8080/tieba");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}else {
Toast.makeText(this, "沒有目標(biāo)界面", Toast.LENGTH_SHORT).show();
}
}
/**
* 判斷是否安裝了應(yīng)用
* @return true 為已經(jīng)安裝
*/
private boolean hasApplication() {
PackageManager manager = getPackageManager();
Intent action = new Intent(Intent.ACTION_VIEW);
action.setData(Uri.parse("bruce://baidu:8080/tieba"));
List list = manager.queryIntentActivities(action, PackageManager.GET_RESOLVED_FILTER);
return list != null && list.size() > 0;
}
}
D應(yīng)用的activit代碼如下:
/**
* DATE:2018/3/22
* USER: liuzj
* DESC:
* email:liuzj@hi-board.com
*/
public class SchemeTargetActivity extends AppCompatActivity {
private static final String TAG = "SchemeTargetActivity";
private TextView text;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scheme);
text = (TextView) findViewById(R.id.tv);
Uri uri = getIntent().getData();
if (uri != null) {
dispatchUri(uri);
} else {
Log.e(TAG, "Uri is null");
}
}
/**
* 這里可以做一些獲取你從uri中設(shè)置的信息
*
* @param uri
*/
private void dispatchUri(Uri uri) {
String uriStr = uri.toString();
Log.e(TAG, "dispatchUri: 39---" + uriStr);
Log.e(TAG, "dispatchUri: 40---" + uri.getScheme());
text.setText(uri.getScheme());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
Log.e(TAG, "onNewIntent: 48--------" + uri.toString());
text.setText(uri.toString());
}
}
你以為到了這里就要結(jié)束了嗎?怎么可能。我們來玩一玩通過短信鏈接來打開應(yīng)用
把協(xié)議改一改
<activity
android:name=".SchemeTargetActivity"
android:launchMode="singleTask">
<!-- 要想在別的App上能成功調(diào)起App,必須添加intent過濾器 -->
<intent-filter>
<!-- 協(xié)議部分 可以隨便設(shè)置 還可以加一些host port path 等,協(xié)議規(guī)則越詳細(xì)定位界面更精確,-->
<!--<data android:scheme="bruce"></data>-->
<data
android:scheme="bruce"
android:host="mytest.com"
android:path="/get"
>
</data>
<!-- 必須設(shè)置 -->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- 如果需要外部網(wǎng)頁打開本頁面,還需要設(shè)置這個 -->
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
其實scheme設(shè)置成http也是可以的但是怕用戶會通過瀏覽器去打開,所以為了避免這種問題這里的scheme我們自己寫一個
寫個html
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="Refresh" content="0;url=bruce://mytest.com/get" />
<title>Android測試</title>
</head>
<body>
</body>
</html>
即只要點擊網(wǎng)址我們就會重定向去打開app,前端代碼寫的不好,多見諒。實際開發(fā)中前端代碼還可通過超時判斷用戶是否安裝了app,沒有安裝就去下載頁面,安裝了app就可以打開app跳轉(zhuǎn)到該頁面。