Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android產品研發(十一)--)應用內跳轉scheme協議

android產品研發(十一)--)應用內跳轉scheme協議

編輯:關於Android編程

本文講解的是一種App內頁面跳轉協議,這裡的跳轉包括應用內跳轉、H5與Native跳轉,服務器通知客戶端如何跳轉等。

在講解應用內跳轉協議之前我們先講解一下H5與Native相互跳轉的相關知識點。現在越來越多的App采用了Native + H5方式開發,其中Native與H5頁面如何交互?google提供了一個公共的方式:js與native互調,即js可以調用Native方法,Native同樣也可以調用js方法;

但是這種交互方式存在著不少問題:
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對象注入漏洞…(不清楚的可以google)

基於這種種的原因,我們並未采用這種方式用於Native與webview交互,而是采用scheme + cookie的方式;

這裡的scheme是一種頁面內跳轉協議,主要用於支持一下幾種場景:

服務器下發跳轉路徑,客戶端根據服務器下發跳轉路徑跳轉相應的頁面;

H5頁面點擊錨點,根據錨點具體跳轉路徑App端跳轉具體的頁面;

App端收到服務器端下發的PUSH通知欄消息,根據消息的點擊跳轉路徑跳轉相關頁面

下面我將簡單介紹一下scheme的基本概念以及以上三種場景下scheme的具體應用。

URL scheme 概述

URL scheme 的作用

客戶端應用可以向操作系統注冊一個 URL scheme,該 scheme 用於從浏覽器或其他應用中啟動本應用。通過指定的 URL 字段,可以讓應用在被調起後直接打開某些特定頁面,比如車輛詳情頁、訂單詳情頁、消息通知頁、促銷廣告頁等等。也可以執行某些指定動作,如訂單支付等。也可以在應用內通過 html 頁來直接調用顯示 app 內的某個頁面。

URL scheme 的格式

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

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

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

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

Scheme定義Activity

1)在androidmanifest.xml中定義scheme


        

            
            

                
                
                
                
                

                
            
        

這樣我們便定義了能夠接受scheme請求的activity實例,當網頁或者是android代碼發送這種規則scheme的請求的時候就能夠吊起NativeAppActivity了。

2)當然就是實現NativeAppActivity

/**
 * Created by admin
 */
public class NativeAppActivity extends Activity{
    public String tag = "NativeAppActivity";
    public Activity mContext = null;

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

}

NativeAppActivity這個類中主要用於實現對scheme的解析,然後做出相應的動作,比如請求scheme跳轉登錄頁面,我們可以這樣定義

uumobile://appname/gotoLogin

然後我們解析出scheme如果是這樣的結構就跳轉登錄頁面。。。

這裡簡單說一下,我們可以通過Intent對象獲取調用的scheme的host等信息

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

3)通過服務器下發跳轉路徑跳轉相應頁面

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

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

4)通過在H5頁面的錨點跳轉相應的頁面

@Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        //解析scheme
        if (url.indexOf(H5Constant.SCHEME) != -1) {
            try {
                Uri uri = Uri.parse(url);
                String[] urlSplit = url.split("\\?");
                Map queryMap = new HashMap();
                String h5Url = null;
                if (urlSplit.length == 2) {
                    queryMap = H5Constant.parseUriQuery(urlSplit[1]);
                    h5Url = queryMap.get(H5Constant.MURL);
                }
                // 跳轉NativeAppActivity解析
                {
                    // 若設置刷新,則刷新頁面
                    if (queryMap.containsKey(H5Constant.RELOADPRE) && "1".equals(queryMap.get(H5Constant.RELOADPRE))) {
                        h5Fragment.isNeedFlushPreH5 = true;
                    }
                    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                    h5Activity.startActivityForResult(intent, H5Constant.h5RequestCode);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
        // 打電話
        else if (url.indexOf("tel://") != -1) {
            final String number = url.substring("tel://".length());
            Config.callPhoneByNumber(h5Activity, number);
            return true;
        } else if (url.indexOf("tel:") != -1) {
            final String number = url.substring("tel:".length());
            Config.callPhoneByNumber(h5Activity, number);
            return true;
        }
        // 其他跳轉方式
        else {
            view.loadUrl(url);
            //如果不需要其他對點擊鏈接事件的處理返回true,否則返回false
            return false;
        }
    }

可以發現我們為Webview設置了WebViewClient,並重寫了WebViewClient的shouldOverrideUrlLoading方法,然後我們解析錨點的url,並根據解析的內容調起NativeAppActivity的scheme Activity,然後在NativeAppActivity中解析scheme的內容並跳轉相應的頁面。

5)根據服務器下發通知欄消息,App跳轉相應的頁面

public class NotificationActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        L.i("接收到通知點擊事件...");
        Intent realIntent = getIntent().getParcelableExtra(NotifeConstant.REAL_INTENT);
        // 解析scheme並跳轉
        gotoRealScheme(this, realIntent);
    }


    /**
     * notification中跳轉SCHEME,根據有效時間判斷跳轉URL地址
     *  跳轉之後更具網絡請求判斷用戶當前狀態
     */
    private void gotoRealScheme(Context context, Intent realIntent) {
        if (realIntent == null || context == null) {
            finish();
            return;
        }
        try {
            L.i("開始解析通知中的參數...");
            long startShowTime = realIntent.getLongExtra(NotifeConstant.START_SHOW_TIME, 0);
            // 有效期時間,單位:s(秒)
            long validTime = realIntent.getLongExtra(NotifeConstant.VALID_TIME, 0);
            long currentTime = System.currentTimeMillis();
            String validActionUrl = realIntent.getStringExtra(NotifeConstant.VALID_ACTION_URL);
            String invalidActionUrl = realIntent.getStringExtra(NotifeConstant.INVALID_ACTION_URL);
            Intent schemeIntent;
            L.i("開始根據URL構建Intent對象...");
            if ((currentTime - startShowTime) / 1000L <= validTime) {
                schemeIntent = H5Constant.buildSchemeFromUrl(validActionUrl);
            } else {
                schemeIntent = H5Constant.buildSchemeFromUrl(invalidActionUrl);
            }
            if (schemeIntent != null) {
                // 設置當前頁面為通知欄打開
                Config.isNotificationOpen = true;
                context.startActivity(schemeIntent);
                finish();
                //對通知欄點擊事件統計
                MobclickAgent.onEvent(context, UMCountConstant.PUSH_NOTIFICATION_CLICK);
            } else {
                finish();
            }
        } catch (Exception e) {
            // 異常情況下退出當前Activity
            finish();
        }
    }
}

服務器下發的所有的通知都是先跳轉這裡的NotificationActivity,然後在這裡執行跳轉其他Activity的邏輯,而這裡的H5Constant的buildSchemeFromUrl方法就是構造跳轉頁面Intent對象的,我們可以看一buildSchemeFromUrl方法的具體實現:

/**
     * 從scheme的url中構建出Intent,用於界面跳轉
     *
     * @param url
     * @return
     */
    public static Intent buildSchemeFromUrl(String url) {
        if (url != null && url.indexOf(H5Constant.SCHEME) != -1) {
            Uri uri = Uri.parse(url);
            String[] urlSplit = url.split("\\?");
            Map queryMap = new HashMap();
            String h5Url = null;
            if (urlSplit.length == 2) {
                queryMap = H5Constant.parseUriQuery(urlSplit[1]);
                h5Url = queryMap.get(H5Constant.MURL);
            }
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            if (!TextUtils.isEmpty(h5Url)) {
                intent.putExtra(H5Constant.MURL, h5Url);
            }
            return intent;
        }
        return null;
    }

這樣我們就搞構造除了跳轉NativeAppActivity的Intent對象,並將scheme字符串傳遞給了NativeAppActivity,這樣在NativeAppActivity中就可以解析scheme字符串並執行相應的跳轉邏輯了。

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


本文以同步至github中:https://github.com/yipianfengye/androidProject,歡迎star和follow


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved