大家都知道,如果我們想要打開手機本地的其他應用,我們可以通過intent的隱式啟動,添加相關界面activity的包路徑,來打開對應的應用和其界面。但這并不是萬能的,因為一來別人家的APP的包路徑,不通過逆向手段是無法獲知的,二來如果其打開界面本就需要傳遞一些參數才能正常開啟,字段key你也不知道。
所以,Android系統也知道這種情況,所以才有了scheme這樣的東西來方便我們的應用提供一個入口供別人開啟。
廢話不多說先上demo地址
這篇文章主要講述
一、提供scheme供別人打開自己的應用
二、webview中的網頁鏈接打開應用
三、有哪些現成的scheme url
四、相關注意事項
一、通過scheme提供開啟自己應用的入口:
方法很簡單:
在AndroidManifest.xml文件中的activity標簽中添加intent-filter,并且添加data的scheme、host等,如圖
注意:在MainActivity中要新寫一個intent-filter,如果直接寫在launcher打開的filter中則會app圖標消失(因為category被覆蓋為DEAFAULT)
這樣就可以通過以下代碼打開我們自己的app了
String url = "jafir://main.app"
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(in);
我們還可以通過這個url鏈接傳遞參數
傳遞參數有啥用呢?比如打開QQ的與某人的聊天界面,你肯定要傳遞一個qq號
所以打開qq的鏈接一般為:
mqqwpa://im/chat?chat_type=wpa&uin=522648467
String url = "jafir://main.app?key=傳遞的參數"
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(in);
然后在MainActivity中通過如下代碼獲得
Intent intent = getIntent();
String scheme = intent.getScheme();
Uri uri = intent.getData();
System.out.println("scheme:"+scheme);
if (uri != null) {
String host = uri.getHost();
String dataString = intent.getDataString();
//獲得參數值
String key1 = uri.getQueryParameter("key1");
}
效果圖:
二、 webview中鏈接打開應用
我們都知道現在的網頁web一般開啟三方應用,比如開啟迅雷,開啟QQ臨時對話等等,這些都是網頁鏈接,但是網頁鏈接確可以打開Android本地應用(前提是瀏覽器支持)。一個網頁鏈接可以做到在電腦瀏覽器上打開PC軟件,在手機瀏覽器上又是打開app,這是怎么回事呢?原因稍后解釋
在Android的webview中本是不支持直接打開本地應用的,所以我們就要自己來處理。
String url = "http://wpa.qq.com/msgrd?v=3&uin=522648467&site=qq&menu=yes";
WebViewClient webViewClient = new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
if (url.startsWith("http") || url.startsWith("https")) { //http和https協議開頭的執行正常的流程
return false;
} else { //其他的URL則會開啟一個Acitity然后去調用原生APP
Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (in.resolveActivity(getPackageManager()) == null) {
//說明系統中不存在這個activity
view.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "應用未安裝", Toast.LENGTH_SHORT).show();
view.loadUrl(failUrl);
}
});
} else {
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startActivity(in);
//如果想要加載成功跳轉可以 這樣
view.post(new Runnable() {
@Override
public void run() {
view.loadUrl(successUrl);
}
});
}
return true;
}
}
};
webView = (WebView) findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(webViewClient);
webView.loadUrl(url);
網上的方法,普遍為這種:
通過在重定向的時候判斷是否是普通的網頁鏈接,如果不是則為scheme調用的這種,則我們自己來處理為intent跳轉開啟
tips:
可以在成功的時候再view.post(new Runnable() { @Override public void run() { view.loadUrl(successUrl); } });
然后就會自動跳轉到成功的界面。successUrl是我本地的assets里面寫的一個成功的html界面
同理 可以在應用未安裝失敗的時候再//說明系統中不存在這個activity view.post(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this,"應用未安裝",Toast.LENGTH_SHORT).show(); view.loadUrl(failUrl); } });
然后就會自動跳轉到失敗的提示界面。failUrl是我本地的assets里面寫的一個失敗提示的html界面
測試通過網頁鏈接打開QQ:
注意:
我們在打印重定向url的時候發現,qq的url重定向了幾次,最終在手機瀏覽器上呈現的形式就是scheme的形式:mqqwpa://im/chat?chat_type=wpa&uin=522648467
為什么要重定向呢?就回到了之前上面提的那個問題,網頁上使用的url:http://wpa.qq.com/msgrd?v=3&uin=793563805&site=qq&menu=yes這個在電腦瀏覽器上可以直接打開PC的qq,但是在手機上,重定向就是在判斷和甄別是否是手機瀏覽器,如果是的話就會把url重定向為scheme形式的鏈接。
并且這里要注意:如果shouldOverrideUrlLoading返回的不是true,而是super,那么你會驚奇的發現,qq直接重定向到它自己的應用寶去了,哈哈,有點惡心
測試:
我們在本地assets里面建一個html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JavaScript HTML App</title>
</head>
<body>
<!--<h1>已經打開APP啦!!!!</h1>-->
<a target="_blank" href=" http://wpa.qq.com/msgrd?v=3&uin=522648467&site=qq&menu=yes">打開qq</a>
</body>
</html>
然后直接打開
webview.loadUrl("file:///android_asset/index.html");
模擬webview中點擊鏈接打開qq應用
注意:
1、我們要想打開指定qq的臨時聊天界面,需要那個qq已經開通了臨時聊天界面,不然會報錯。
在這里開啟的推廣工具中免費開通,不然的話它重定向的url就不是mqqwpa://chat... 而是 tencent://message...去了,直接調用intent就找不對對應的activity然后crash,所以要確保你的對應qq號是已經開通了臨時聊天的(推廣)。
2、如果你想要點擊了開啟應用然后跳轉到別的網頁鏈接可以這么做
//在shouldInterceptRequest中重新加載
view.post(new Runnable() {
@Override
public void run() {
view.loadUrl(localUrl);
}
});
注意:因為webview的攔截線程不在主線程,所以可以用webview.post(new runnable(){})來實現
效果圖:由于模擬器上面沒有x86 qq 所以,效果的話,你自己運行demo然后在手機上試吧
有哪些應用的scheme url
我這里整理了一下,有點多,沒有全部測試過(網上搜羅而來,并非原創)
QQ的url是 mqq://
微信是weixin://
淘寶taobao://
點評dianping://
dianping://search
微博 sinaweibo://
名片全能王camcard://
weico微博weico://
支付寶alipay://
豆瓣fm:doubanradio://
微盤 sinavdisk://
網易公開課ntesopen://
美團 imeituan://
京冬openapp.jdmoble://
人人renren://
我查查 wcc://
1號店wccbyihaodian://
有道詞典yddictproapp://
知乎zhihu://
優酷 youku://
四、注意事項
其實寫到最后發現,那些注意事項基本都是寫到各項里面去了,覺得那樣會好點。
這里就寫寫思路吧:
我們的應用如果需要提供給別人數據,那么用的是contentProvider內容提供者,如果是供別人打開的話用的是scheme url intent隱式打開,這里就就涉及到相關的一些被別人開啟和使用的知識,聯想到比如launchMode,提供給別人使用的界面一般情況下可能是用singleTask 或者某些特殊的會使用singleInstance,再者再深一點的還有taskAffinity相關,哪些提供出來的獨立的界面在自己的任務棧還是在指定的任務棧里面,這些統統都是跟 提供 有關聯。
最后
總之,我在寫博客的之前并沒有想到我要寫這篇博客,但是在一步一步實踐探索那些知識的時候確實就是踩了一些坑,所以還是想要記錄下來分享,又想不能做的太水,于是要求內容稍微飽滿,就這樣逐漸逐漸思維發散,然后拼接整理,最終落下此文。
ps:如果文中有錯誤,請指正,謝謝。也歡迎廣提意見,思維發散。