在Android開發(fā)中,不同Activity之間的跳轉(zhuǎn)和切換是很常見的,這使得APP的內(nèi)容更加豐富,功能更為多樣,但是一個應(yīng)用所能包括的功能畢竟有限,在很多的場景下需要跨應(yīng)用調(diào)用,比如在應(yīng)用中跳轉(zhuǎn)到微信支付的頁面,或者使用第三方賬號登陸時跳轉(zhuǎn)到QQ登陸等等。這樣的情況下,要跳轉(zhuǎn)的Activity或者Application是第三方開發(fā)的,很可能不知道要具體跳轉(zhuǎn)到哪一個Activity中,或者直接跳轉(zhuǎn)并不安全,諸如這些問題都需要在跨應(yīng)用間調(diào)用時被周全地考慮到。為了更好地解決這一問題,下面就來介紹Android中的URL Scheme協(xié)議
URL Scheme簡介
Android中的自定義的URL Scheme是一種頁面內(nèi)跳轉(zhuǎn)協(xié)議,也可以被稱為URLRouter,就是通過類似打開網(wǎng)頁的方式去通過路由打開一個Activity,而非直接通過顯式Intent方式去進行跳轉(zhuǎn)。這樣隱式intent的方法跳轉(zhuǎn)好處如下:
- 降低耦合性:不需要知道具體要跳轉(zhuǎn)哪個界面,只需要根據(jù)需求,按照約定好的URL路由協(xié)議發(fā)送Intent即可;
- 更為安全:不顯示Intent跳轉(zhuǎn),只要是符合協(xié)議的Intent都會有對應(yīng)的Activity來匹配,避免了跳轉(zhuǎn)到不該出現(xiàn)的頁面;
- 更為靈活: 有著更為廣泛的應(yīng)用場景,一下場景中都可以使用URL Scheme
- 服務(wù)器下發(fā)跳轉(zhuǎn)路徑,客戶端根據(jù)服務(wù)器下發(fā)跳轉(zhuǎn)路徑跳轉(zhuǎn)相應(yīng)的頁面
- H5頁面點擊錨點,根據(jù)錨點具體跳轉(zhuǎn)路徑APP端跳轉(zhuǎn)具體的頁面
- APP端收到服務(wù)器端下發(fā)的PUSH通知欄消息,根據(jù)消息的點擊跳轉(zhuǎn)路徑跳轉(zhuǎn)相關(guān)頁面
- APP根據(jù)URL跳轉(zhuǎn)到另外一個APP指定頁面
URL Scheme協(xié)議格式
上文已經(jīng)說過,URL Scheme是就通過類似打開網(wǎng)頁的方式去通過路由打開一個Activity,其協(xié)議格式和我們打開網(wǎng)頁輸入的網(wǎng)址類似。
一個完整的完整的URL Scheme協(xié)議格式由scheme、host、port、path和query組成,其結(jié)構(gòu)如下所示:
<scheme>://<host>:<port>/<path>?<query>
其中scheme既可以是Android中常見的協(xié)議,也可以是我們自定義的協(xié)議。Android中常見的協(xié)議包括content協(xié)議、http協(xié)議、file協(xié)議等,自定義協(xié)議可以使用自定義的字符串,當(dāng)我們啟動第三方的應(yīng)用時候,多是使用自定義協(xié)議。
如下是一個自定義協(xié)議的URI:
通過上面的路徑 Scheme、Host、port、path、query全部包含:
- xl,即為Scheme,代表該Scheme 協(xié)議名稱
- goods,即為Host,代表Scheme作用于哪個地址域
- 8888,即為port,代表該路徑的端口號
- goodsDetail,即為path, 代表Scheme指定的頁面
- goodsId,即為query,代表傳遞的參數(shù)
URL Scheme的使用方法
URL Scheme的使用方法簡要言之就是先在manifest中配置能接受Scheme方式啟動的activity;當(dāng)需要調(diào)用時,將Scheme協(xié)議的URi以Data的形式加入到Intent中,隱式調(diào)用該activity。
1). 在AndroidManifest.xml中對<activity >標(biāo)簽增加<intent-filter>設(shè)置Scheme
<activity android:name=".MainActivity">
<intent-filter> <!--正常啟動-->
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter> <!--URL Scheme啟動-->
<!--必有項-->
<action android:name="android.intent.action.VIEW"/>
<!--如果希望該應(yīng)用可以通過瀏覽器的連接啟動,則添加該項-->
<category android:name="android.intent.category.BROWSABLE"/>
<!--表示該頁面可以被隱式調(diào)用,必須加上該項-->
<category android:name="android.intent.category.DEFAULT"/>
<!--協(xié)議部分-->
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
<intent-filter>
<action android:name="emms.intent.action.check_authorization"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="emms.intent.category.authorization"/>
</intent-filter>
</activity>
上面的設(shè)置中可以看到,MainActivity包含多個<intent-filter>設(shè)置,第一個是正常的啟動,也就是在應(yīng)用列表中啟動;第二個是通過URL Scheme方式啟動,其本身也是隱式Intent調(diào)用的一種,不同在于添加了<data>屬性,定義了其接受URL Scheme協(xié)議格式為urlschemel://auth_activity
這里需要說明下,URL Scheme協(xié)議格式中,組成URI的這些屬性在<data >標(biāo)簽中都是可選的 ,但存在如下的依賴關(guān)系:
- 如果沒有指定scheme,那么host參數(shù)會被忽略
- 如果沒有指定host,那么port參數(shù)會被忽略
- 如果scheme和host都沒有指定,path參數(shù)會被忽略
當(dāng)我們將intent對象中的Uri參數(shù)與intent-filter中的<data>標(biāo)簽指定的URI格式進行對比時,我們只對比intent-filter的<data>標(biāo)簽指定的部分,例如:
- 如果intent-filter中只指定了scheme,那么所有帶有該sheme的URI都能匹配到該intent-filter。
- 如果intent-filter中只指定了scheme和authority(authority包括host和port兩部分)而沒有指定path,那么所有具有相同scheme和authority的URI都能匹配到該intent-filter,而不用考慮path為何值。
- 如果intent-filter中同時指定了scheme、authority和path,那么只有具有相同scheme、authority和path的URI才能匹配到該intent-filter。
需要注意的是,intent-filter的<data>標(biāo)簽在指定path的值時,可以在里面使用通配符*,起到部分匹配的效果。
2). 使用URL啟動Activity
Uri data = Uri.parse("urlschemel://auth_activity");
Intent intent = new Intent(Intent.ACTION_VIEW,data);
//保證新啟動的APP有單獨的堆棧,如果希望新啟動的APP和原有APP使用同一個堆棧則去掉該項
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivityForResult(intent, RESULT_OK);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "沒有匹配的APP,請下載安裝",Toast.LENGTH_SHORT).show();
}
當(dāng)然可以在網(wǎng)頁中調(diào)用
<a href="urlschemel://auth_activity">打開新的應(yīng)用</a>
或者是在JS中調(diào)用
window.location = "urlschemel://auth_activity";
3.)如何判斷URL Scheme是否有效
boolean checkUrlScheme(Intent intent){
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
return !activities.isEmpty();
}
將子APP在Home Launcher中隱藏
有時候需要把一些輔助性的、較為獨立的APP在Home Launcher中隱藏起來,只允許一些特定的APP調(diào)用。這個時候,我們可以利用URL Scheme協(xié)議來做到這一點,設(shè)置AndroidManifest.xml中對<activity >標(biāo)簽如下
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.BROWSABLE"/>
<!--表示該頁面可以被隱式調(diào)用,必須加上該項-->
<category android:name="android.intent.category.DEFAULT"/>
<!--協(xié)議部分-->
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
</activity>
因為Home Launcher列出的應(yīng)用圖標(biāo)要求必須有Activity同時滿足
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
上面的配置中有多余的category和data限制存在,所以并不匹配,不會在Home Launcher出現(xiàn),但是可以使用URL Scheme來啟動。
Uri data = Uri.parse("urlschemel://auth_activity");
Intent intent = new Intent(Intent.ACTION_MAIN,data);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
這樣就可以將一組APP設(shè)置一個統(tǒng)一的入口,然后根據(jù)實際需要在調(diào)用不同子APP,即所謂的APP業(yè)務(wù)組件化,URL Scheme在其中有著重要的作用,更進一步討論會在以后的文章中呈現(xiàn),敬請期待。
參考文獻:
http://blog.csdn.net/iispring/article/details/48481793
http://blog.csdn.net/hb707934728/article/details/53196419
http://www.cnblogs.com/whoislcj/p/5825333.html