Android应用内跳转Scheme协议
之前一篇文章WebView使用解析(一)之基本用法我講過了WebView與JS交互的方式,JS調用Java代碼主要是通過對象注入的方式實現的,即使用addJavascriptInterface。而JAVA調用JS代碼則是通過javascript:偽協議來實現的,即javascript:methodName(params……)。
但是這種交互方式存在著不少問題:
- 1、Java 調用 js 里面的函數,效率并不是很高,估計要200ms左右,做交互性很強的事情這種速度很難讓人接受。而js去調Java的方法,速度很快,50ms左右,所以盡量用js調用Java方法。
- 2、Java 調用 js 的函數,沒有返回值,調用了就控制不到了。
- 3、Js 調用 Java 的方法,返回值如果是字符串,你會發現這個字符串是 native 的,轉成 locale 的才能正常使用,使用 toLocaleString() 函數就可以了,不過這個函數的速度并不快、轉化的字符串如果很多、將會很耗費時間。
- 4、網頁中盡量不要使用jQuery,執行起來需要5-6秒,最好使用原生的js寫業務腳本,以提升加載速度、改善用戶體驗。
- 5、Android4.2以下的系統存在著webview的js對象注入漏洞。
這里我給大家介紹另外一種Native與webview的交互方式,采用scheme的方式。
URL scheme
URI與Uri
URI位置在java.net.URI,顯然是Java提供的一個類。而Uri位置在android.net.Uri,是由Android提供的一個類。所以初步可以判斷,Uri是URI的“擴展”以適應Android系統的需要。
概述
android中的scheme是一種頁面內跳轉協議,是一種非常好的實現機制,通過定義自己的scheme協議,可以非常方便跳轉app中的各個頁面;通過scheme協議,服務器可以定制化告訴App跳轉那個頁面,可以通過通知欄消息定制化跳轉頁面,可以通過H5頁面跳轉頁面等。
應用場景
客戶端應用可以向操作系統注冊一個URL Scheme,該scheme用于從瀏覽器或其他應用中啟動本應用,通過scheme協議來跳轉到相應的APP界面,比如商品詳情,活動詳情,商家詳情等等界面。也可以執行某些指定動作,如完成支付等。也可以在應用內部通過H5頁面來直接跳轉APP某個界面。
URL Scheme應用場景分為以下4種:
- 服務器下發跳轉路徑,客戶端根據服務器下發跳轉路徑跳轉相應的頁面
- H5頁面點擊描點,根據描點具體跳轉路徑APP端跳轉具體的頁面
- APP端收到服務器端下發的PUSH通知欄消息,根據消息的點擊跳轉路徑跳轉相關頁面
格式
[scheme:][//host:port][path][?query][#fragment]
URL Scheme 屬性分為:scheme,host,port,path,query,fragment
test://shangjia:8888/shangjiaDetail?shangjiaId=222#watson scheme : test host : shangjia port : 8888 path : /shangjiaDetail query : shangjiaId=222 fragment : watson注:
1.除了scheme、host是必須要有的,其它的幾個port 、path、query、fragment,它們每一個可以選擇性的要或不要,但順序不能變。
2.其中[host:port]部分我們也可以稱為authority。
3.在scheme和fragment之間的部分我們也可以稱為scheme-specific-part。
代碼提取
上面我們通過實例講解了肉眼識別Uri更部分的方式,但在代碼中又要怎樣提取呢。下面就看看Uri中提取各部分的接口,我們換一個Uri字符串:
http://www.java.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#watsongetScheme() :獲取Uri中的scheme字符串部分,在這里即http
getSchemeSpecificPart():獲取Uri中的scheme-specific-part:部分,這里是://www.java.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4
getFragment():獲取Uri中的Fragment部分,即watson
getAuthority():獲取Uri中Authority部分,即www.java.com:8080
getPath():獲取Uri中path部分,即/yourpath/fileName.htm
getQuery():獲取Uri中的query部分,即stove=10&path=32&id=4
getHost():獲取Authority中的Host字符串,即www.java.com
getPost():獲取Authority中的Port字符串,即8080
另外還有兩個常用的:getPathSegments()、getQueryParameter(String key)
List< String> getPathSegments():上面我們的getPath()是把path部分整個獲取下來:/yourpath/fileName.htm,getPathSegments()的作用就是依次提取出Path的各個部分的字符串,以字符串數組的形式輸出。
getQueryParameter(String key):在上面我們通過getQuery()獲取整個query字段:stove=10&path=32&id=4,getQueryParameter(String key)作用就是通過傳進去path中某個Key的字符串,返回他對應的值。
scheme 使用
AndroidMainfest.xml 配置 scheme
<application android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"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></activity><!--服務器下發跳轉路徑跳轉Activity--><activity android:name=".GoodsDetailActivity"android:theme="@style/AppTheme"><intent-filter><!--協議部分,隨便設置--><data android:scheme="watson" android:host="goods" android:path="/goodsDetail" android:port="8888"/><!--下面這兩項必須得設置--><category android:name="android.intent.category.DEFAULT"/><action android:name="android.intent.action.VIEW"/></intent-filter></activity><!--H5頁面點擊描點跳轉Activity--><activity android:name=".LoginActivity"><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:host="login"android:scheme="test" /><data android:host="start"android:scheme="test" /> </intent-filter></activity></application>這樣我們便定義了能夠接受scheme請求的activity實例,當網頁或者是Android代碼發送這種規則scheme的請求的時候就能夠調用起對應的Activity了。
通過服務器下發跳轉路徑跳轉相應頁面
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("watson://goods:8888/goodsDetail?goodsId=10011002")); startActivity(intent);這里的”watson://goods:8888/goodsDetail?goodsId=10011002”就是服務器下發的跳轉路徑,當我們執行startActivity的時候就會調起GoodsDetailActivity,然后我們可以在GoodsDetailActivity種解析出scheme的內容,再做相應處理。
public class GoodsDetailActivity extends Activity{public String TAG = "huaxun";public void onCreate(Bundle b) {super.onCreate(b);setContentView(R.layout.activity_detail);Uri uri = getIntent().getData();if (uri != null) {// 完整的url信息String url = uri.toString();Log.e(TAG, "url: " + uri);// scheme部分String scheme = uri.getScheme();Log.e(TAG, "scheme: " + scheme);// host部分String host = uri.getHost();Log.e(TAG, "host: " + host);//port部分int port = uri.getPort();Log.e(TAG, "port: " + port);// 訪問路徑String path = uri.getPath();Log.e(TAG, "path: " + path);// Query部分String query = uri.getQuery();Log.e(TAG, "query: " + query);//獲取指定參數值String goodsId = uri.getQueryParameter("goodsId");Log.e(TAG, "goodsId: " + goodsId);}} }看Log信息:
通過H5頁面的錨點跳轉相應的頁面
首先需要一個HTML文件:
<!DOCTYPE html> <html> <head><title>Js調用Android</title> </head><body> <a href="test://start/?id=431&name=watson&age=29">跳轉start</a> <a href="test://web/?id=432&name=jack&age=28">跳轉web</a> <a href="test://login/?id=433&name=tom&age=27">跳轉Login</a> </body> </html>Java中需要加載這個本地頁面,并設置WebViewClient。
web.loadUrl("file:///android_asset/web.html");web.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {Log.v("huaxun","view = [" + view + "], url = [" + url + "]");Uri uri = Uri.parse(url);String id = uri.getQueryParameter("id");String name = uri.getQueryParameter("name");String age = uri.getQueryParameter("age");Log.v("huaxun","id:" + id);Log.v("huaxun","name:" + name);Log.v("huaxun","age:" + age);if (url.startsWith("test://login")) {Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("test://login/userDetail?id="+id+"&name="+name+"&age="+age));startActivity(intent);}return true;}可以發現我們為Webview設置了WebViewClient,并重寫了WebViewClient的shouldOverrideUrlLoading方法,然后我們解析錨點的url,并根據解析的內容調起LoginActivity。
如果我們不想設置WebViewClient,當點擊H5頁面的錨點url也是可以直接跳轉Activity的,是怎么實現的呢?
(1)Intent-filter中的各種匹配工作,還應該加上一個屬性:
(2)點擊的url需要和Mainfest中LoginActivity配置的Scheme等數據相對應。
只要實現了以上兩點就可以點擊url輕松實現跳轉。但是還是不建議這么做,因為在項目中可能URL Scheme協議并不止一個界面。如果你在AndroidMainfest.xml里面去給每一個可能相關的界面都配置scheme屬性,那你整個界面看著也不美觀,而且還都是重復的配置。所以還是建議根據URL地址來判斷跳轉。
根據服務器下發通知跳轉相應的界面
同樣的邏輯。把服務器下發的通知欄消息,里面的URL地址數據拿到,進行解析判斷,然后跳轉到相應的界面。
NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);NotificationCompat.Builder builder;builder = new NotificationCompat.Builder(MainActivity.this);builder.setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentTitle("watson").setContentText("test schemeURL").setTicker("有新消息").setOngoing(false).setWhen(System.currentTimeMillis()).setPriority(Notification.PRIORITY_DEFAULT).setAutoCancel(true);Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("watson://goods:8888/goodsDetail?goodsId=10011002"));PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);builder.setContentIntent(pendingIntent);Notification notification = builder.build();notifyManager.notify(1, notification);有關Notification的知識,我就不再講了,最重要的是PendingIntent的封裝!
DEMO下載地址
總結
以上是生活随笔為你收集整理的Android应用内跳转Scheme协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对抗Windows Defender的方
- 下一篇: 通过完全由有理数构成的区间套来揭示无理数