1. 程式人生 > >Scheme詳解( web頁面判斷是否安裝某app,並判斷是否開啟該應用)

Scheme詳解( web頁面判斷是否安裝某app,並判斷是否開啟該應用)

參照頁面:

demo例項:http://blog.csdn.net/qq_30740239/article/details/51969660

Scheme詳解:http://blog.csdn.net/wangkeke1860/article/details/49850997

引數詳解:http://blog.csdn.net/harvic880925/article/details/44679239

web頁面判斷手機裡是否安轉應用的原理就是:首先試著開啟手機端某個app的本地協議;如果超時就轉到app下載頁,下載該app。

下面說說

URL scheme 概述

URL scheme 的作用

客戶端應用可以向作業系統

註冊一個 URL scheme,該 scheme 用於從瀏覽器或其他應用中啟動本應用。通過指定的 URL 欄位,可以讓應用在被調起後直接開啟某些特定頁面,比如車輛詳情頁、訂單詳情頁、訊息通知頁、促銷廣告頁等等。也可以執行某些指定動作,如訂單支付等。也可以在應用內通過 html 頁來直接呼叫顯示 app 內的某個頁面。

URL scheme 的格式

客戶端自定義的 URL 作為從一個應用呼叫另一個的基礎,遵循 RFC 1808 (Relative Uniform Resource Locators) 標準。這跟我們常見的網頁內容 URL 格式一樣。

一個普通的 URL 分為幾個部分,scheme

hostrelativePathquery

比如:http://www.baidu.com/s?rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709,這個URL中,scheme 為 httphost 為www.baidu.comrelativePath 為 /squery 為 rsv_bp=1&rsv_spt=1&wd=NSurl&inputT=2709

一個應用中使用的 URL 例子(該 URL 會調起車輛詳情頁):uumobile://mobile/carDetail?car_id=123456,其中 scheme

 為 uumobilehost 為mobilerelativePath 為 /carDetailquery 為 car_id=123456

Scheme定義Activity

1)在androidmanifest.xml中定義scheme

<!-- 啟動頁 -->
<activity
android:name="com.qiyuan.congmingtou.activity.SplashActivity"
android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
<!-- 要想在別的App上能成功調起App,必須新增intent過濾器 -->
<intent-filter>
<!-- 協議部分,隨便設定 -->
<data android:scheme="cmt" android:host="splash"/>
<!-- 下面這幾行也必須得設定 -->
<category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <action android:name="android.intent.action.VIEW" />
    </intent-filter>
</activity>
這樣我們便定義了能夠接受scheme請求的activity例項,當網頁或者是android程式碼傳送這種規則scheme的請求的時候就能夠吊起SplashActivity了。

2.網頁中Html程式碼和js程式碼

<!doctype html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black"/>

        <title>this's a demo</title>
        <meta id="viewport" name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,minimal-ui">
    </head>
    <body>
        <div>
            <a id="J-call-app" href="JavaScript:;" class="label">立即開啟&gt;&gt;</a>
            <input id="J-download-app" type="hidden" name="storeurl" value="http://m.chanyouji.cn/apk/chanyouji-2.2.0.apk">
        </div>

        <script>
            (function(){
                var ua = navigator.userAgent.toLowerCase();
                var t;
                var config = {
                    /*scheme:必須*/
                    scheme_IOS: 'IfInstalledCongMingTou://congmingtou',
                    scheme_Adr: 'cmt://splash',
                    download_url: document.getElementById('J-download-app').value,
                    timeout: 600
                };

                function openclient() {
                    var startTime = Date.now();

                    var ifr = document.createElement('iframe');


                    ifr.src = ua.indexOf('os') > 0 ? config.scheme_IOS : config.scheme_Adr;
                    ifr.style.display = 'none';
                    document.body.appendChild(ifr);

                    var t = setTimeout(function() {
                        var endTime = Date.now();

                        if (!startTime || endTime - startTime < config.timeout + 200) {
                            window.location = config.download_url;
                        } else {
                            
                        }
                    }, config.timeout);

                    window.onblur = function() {
                        clearTimeout(t);
                    }
                }
                window.addEventListener("DOMContentLoaded", function(){
                    document.getElementById("J-call-app").addEventListener('click',openclient,false);

                }, false);
            })()
        </script>
    </body>
</html>
  如果我們要用於實現對scheme的解析,然後做出相應的動作,比如請求scheme跳轉登入頁面,要在SplashActivity中做寫相應的程式碼:

public class SplashActivity extends Activity{
    public Activity mContext = null;
    public void onCreate(Bundle b)
    {
        super.onCreate(b);
mContext = this;
Uri uri = getIntent().getData();
        if (uri != null)
        {
            List<String> pathSegments = uri.getPathSegments();
String uriQuery = uri.getQuery();
Intent intentif (pathSegments != null && pathSegments.size() > 0) {
                // 解析SCHEME
if (someif) {
                    dosomething();
}
                else {
                    // 若解析不到SCHEME,則關閉NativeAppActivityfinish();
}
            } else {
                finish();
}
        } else {
            finish();
}
    }

}

這裡簡單說一下,我們可以通過Intent物件獲取呼叫的scheme的host等資訊

this.getIntent().getScheme();//獲得Scheme名稱  
this.getIntent().getDataString();//獲得Uri全部路徑 

通過伺服器下發跳轉路徑跳轉相應頁面

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("uumobile://yongche/123123123")));

這裡的”uumobile://yongche/123123123”就是伺服器下發的跳轉路徑,當我們執行startActivity的時候就會調起SpalshActivity,然後我們通過在SpalshActivity解析scheme的內容,跳轉相應的頁面



總結: 
Android中的scheme是一種非常好的實現機制,通過定義自己的scheme協議,可以非常方便跳轉app中的各個頁面; 
通過scheme協議,伺服器可以定製化告訴App跳轉那個頁面,可以通過通知欄訊息定製化跳轉頁面,可以通過H5頁面跳轉頁面等。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

—————————————————————————————————————————————————————————————
---------------------------------------------------------------------------------------------------------------------------------------------------------

一、URI與Uri

大家可能經常會看到在開發時,怎麼有的時候是URI,有的時候是Uri,這是怎麼回事?

名稱如此相像的兩個類是有什麼區別和聯絡?

  • 1.所屬的包不同。URI位置在java.net.URI,顯然是Java提供的一個類。而Uri位置在android.net.Uri,是由Android提供的一個類。所以初步可以判斷,Uri是URI的“擴充套件”以適應Android系統的需要。
  • 2.作用的不同。URI類代表了一個URI(這個URI不是類,而是其本來的意義:通用資源標誌符——Uniform Resource Identifier)例項。Uri類是一個不可改變的URI引用,包括一個URI和一些碎片,URI跟在“#”後面。建立並且轉換URI引用。而且Uri類對無效的行為不敏感,對於無效的輸入沒有定義相應的行為,如果沒有另外製定,它將返回垃圾而不是丟擲一個異常。

看不懂?沒關係,知道這個就可以了:Uri是Android開發的,擴充套件了Java中URI的一些功能來特定的適用於Android開發,所以大家在開發時,只使用Android 提供的Uri即可;

二、Uri結構

(1)、基本形式:

  1. [scheme:]scheme-specific-part[#fragment]  
這裡分為三部分:
scheme、scheme-specific-part、fragment

(2)、進一步劃分:

如果進一步劃分的話是這樣子的

  1. [scheme:][//authority][path][?query][#fragment]  
其中有下面幾個規則:
  • path可以有多個,每個用/連線,比如
    scheme://authority/path1/path2/path3?query#fragment
  • query引數可以帶有對應的值,也可以不帶,如果帶對應的值用=表示,如:
    scheme://authority/path1/path2/path3?id = 1#fragment,這裡有一個引數id,它的值是1
  • query引數可以有多個,每個用&連線
    scheme://authority/path1/path2/path3?id = 1&name = mingming&old#fragment
    這裡有三個引數:
    引數1:id,其值是:1
    引數2:name,其值是:mingming
    引數3:old,沒有對它賦值,所以它的值是null
  • 在android中,除了scheme、authority是必須要有的,其它的幾個path、query、fragment,它們每一個可以選擇性的要或不要,但順序不能變,比如:
    其中"path"可不要:scheme://authority?query#fragment
    其中"path"和"query"可都不要:scheme://authority#fragment
    其中"query"和"fragment"可都不要:scheme://authority/path
    "path","query","fragment"都不要:scheme://authority
    等等……

(3)、終極劃分

其中authority,又可以分為host:port的形式,即再次劃分後是這樣的:

  1. [scheme:][//host:port][path][?query][#fragment]  
所以這是劃分最細的形式,其中host:port用冒號分隔,冒號前的是host,冒號後的port;

三、示例

經過上面的講解,想必大家的Uri的結構就有所瞭解了,下面我們就例項看看各部分的識別方式。

  1. [scheme:]scheme-specific-part[#fragment]  
  2. [scheme:][//authority][path][?query][#fragment]  
  3. [scheme:][//host:port][path][?query][#fragment]  
先列出這三種Uri形式,好讓大家對比;
針對下面一個Uri字串來匹配一下各個部分:
  1. http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
  • scheme:匹對上面的兩個Uri標準形式,很容易看出在:前的部分是scheme,所以這個Uri字串的sheme是:http
  • scheme-specific-part:很容易看出scheme-specific-part是包含在scheme和fragment之間的部分,也就是包括第二部分的[//authority][path][?query]這幾個小部分,所在這個Uri字串的scheme-specific-part是://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4 ,注意要帶上//,因為除了[scheme:]和[#fragment]部分全部都是scheme-specific-part,當然包括最前面的//;
  • fragment:這個是更容易看出的,因為在最後用#分隔的部分就是fragment,所以這個Uri的fragment是:harvic
    下面就是對scheme-specific-part進行拆分了;
    在scheme-specific-part中,最前端的部分就是authority,?後面的部分是query,中間的部分就是path
  • authority:很容易看出scheme-specific-part最新端的部分是:www.java2s.com:8080
  • query:在scheme-specific-part中,?後的部分為:stove=10&path=32&id=4
  • path:在**query:**在scheme-specific-part中,除了authority和query其餘都是path的部分:/yourpath/fileName.htm
    又由於authority又一步可以劃分為host:port形式,其中host:port用冒號分隔,冒號前的是host,冒號後的是port,所以:
  • host:www.java2s.com
  • port:8080

四、程式碼提取

上面我們通過例項講解了肉眼識別Uri更部分的方式,但在程式碼中又要怎樣提取呢。下面就看看Uri中提取各部分的介面,依然以上面的Uri字串為例:

  1. http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic
  • getScheme() :獲取Uri中的scheme字串部分,在這裡即,http
  • getSchemeSpecificPart():獲取Uri中的scheme-specific-part:部分,這裡是://www.java2s.com:8080/yourpath/fileName.htm?
  • getFragment():獲取Uri中的Fragment部分,即harvic
  • getAuthority():獲取Uri中Authority部分,即www.java2s.com:8080
  • getPath():獲取Uri中path部分,即/yourpath/fileName.htm
  • getQuery():獲取Uri中的query部分,即stove=10&path=32&id=4
  • getHost():獲取Authority中的Host字串,即www.java2s.com
  • getPost():獲取Authority中的Port字串,即8080
另外還有兩個常用的:getPathSegments()、getQueryParameter(String key)
  • List< String> getPathSegments():上面我們的getPath()是把path部分整個獲取下來:/yourpath/fileName.htm,getPathSegments()的作用就是依次提取出Path的各個部分的字串,以字串陣列的形式輸出。以上面的Uri為例:
  1. String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id=4#harvic";  
  2. Uri mUri = Uri.parse(mUriStr);  
  3. List<String> pathSegList = mUri.getPathSegments();  
  4. for (String pathItem:pathSegList){  
  5.     Log.d("qijian","pathSegItem:"+pathItem);  
  6. }  
打出來的列表為:

  • getQueryParameter(String key):在上面我們通過getQuery()獲取整個query欄位:stove=10&path=32&id=4,getQueryParameter(String key)作用就是通過傳進去path中某個Key的字串,返回他對應的值。
  1. String mUriStr = "http://www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id#harvic";  
  2. mUri = Uri.parse(mUriStr);  
  3. Log.d(tag,"getQueryParameter(\"stove\"):"+mUri.getQueryParameter("stove"));  
  4. Log.d(tag,"getQueryParameter(\"id\"):"+mUri.getQueryParameter("id"));  
注意注意,我稍微更改了下字串,把query中id的值去掉了!!!!!然後看看通過getQueryParameter("id")獲取它的值會得到什麼!
結果如下:

可以看到,在path中,即使針對某一個KEY不對它賦值是允許的,但在利用getQueryParameter()獲取該KEY對應的值時,獲取到的是null;

五、擴充套件

1、 絕對URI和相對URI

絕對URI:以scheme元件起始的完整格式,如http://fsjohnhuang.cnblogs.com。表示以對標識出現的環境無依賴的方式引用資源。 
相對URI:不以scheme元件起始的非完整格式,如fsjohnhuang.cnblogs.com。表示以對依賴標識出現的環境有依賴的方式引用資源。 

2、不透明URI和分層URI

不透明URI:scheme-specific-part元件不是以正斜槓(/)起始的,如mailto:[email protected]。由於不透明URI無需進行分解操作,因此不會對scheme-specific-part元件進行有效性驗證。 
分層URI:scheme-specific-part元件是以正斜槓(/)起始的,如http://fsjohnhuang.com。