外部開(kāi)啟Activity新姿勢(shì)(scheme)

在H5頁(yè)面瘋狂的今天伍玖,H5和Native的交互就至關(guān)重要嫩痰,而且交互的方式有很多,google提供了一個(gè)公共的方式:js與native互調(diào)窍箍,即js可以調(diào)用Native方法串纺,Native同樣也可以調(diào)用js方法。不過(guò)今天要講的并不是Url攔截的方式和JavaScript注入方式椰棘,因?yàn)檫@種交互方式存在著不少問(wèn)題:

1纺棺、Java 調(diào)用 js 里面的函數(shù)、效率并不是很高邪狞、估計(jì)要200ms左右吧祷蝌、做交互性很強(qiáng)的事情、這種速度很難讓人接受帆卓、而js去調(diào)Java的方法巨朦、速度很快、50ms左右剑令、所以盡量用js調(diào)用Java方法
2糊啡、Java 調(diào)用 js 的函數(shù)、沒(méi)有返回值吁津、調(diào)用了就控制不到了
3棚蓄、Js 調(diào)用 Java 的方法、返回值如果是字符串碍脏、你會(huì)發(fā)現(xiàn)這個(gè)字符串是 native 的癣疟、轉(zhuǎn)成 locale 的才能正常使用、使用 toLocaleString() 函數(shù)就可以了潮酒、不過(guò)這個(gè)函數(shù)的速度并不快睛挚、轉(zhuǎn)化的字符串如果很多、將會(huì)很耗費(fèi)時(shí)間
4急黎、Android4.2以下的系統(tǒng)存在著webview的js對(duì)象注入漏洞
所以處于這些原因扎狱,我們并未采用這種方式用于Native與webview交互侧到,而是要介紹核武器—scheme,采用scheme + cookie的方式淤击。
那你可能會(huì)思考什么是scheme匠抗? 到底哪些場(chǎng)景適合?具體怎么使用污抬?
表要捉急汞贸,慢慢來(lái)介紹。

什么是scheme印机?

客戶端應(yīng)用可以向操作系統(tǒng)注冊(cè)一個(gè) URL scheme矢腻,該 scheme 用于從瀏覽器或其他應(yīng)用中啟動(dòng)本應(yīng)用。通過(guò)指定的 URL 字段射赛,可以讓?xiě)?yīng)用在被調(diào)起后直接打開(kāi)某些特定頁(yè)面多柑,比如車輛詳情頁(yè)、訂單詳情頁(yè)楣责、消息通知頁(yè)竣灌、促銷廣告頁(yè)等等。也可以執(zhí)行某些指定動(dòng)作秆麸,如訂單支付等初嘹。也可以在應(yīng)用內(nèi)通過(guò) html 頁(yè)來(lái)直接調(diào)用顯示 app 內(nèi)的某個(gè)頁(yè)面。

scheme格式沮趣?

客戶端自定義的 URL 作為從一個(gè)應(yīng)用調(diào)用另一個(gè)的基礎(chǔ)屯烦,遵循 RFC 1808 (Relative Uniform Resource Locators) 標(biāo)準(zhǔn)。這跟我們常見(jiàn)的網(wǎng)頁(yè)內(nèi)容 URL 格式一樣兔毒。
先來(lái)個(gè)完整的URL Scheme協(xié)議格式:

xl://goods:8888/goodsDetail?goodsId=10011002
通過(guò)上面的路徑 Scheme、Host甸箱、port育叁、path、query全部包含芍殖,基本上平時(shí)使用路徑就是這樣子的豪嗽。

xl代表該Scheme 協(xié)議名稱
goods代表Scheme作用于哪個(gè)地址域
goodsDetail代表Scheme指定的頁(yè)面
goodsId代表傳遞的參數(shù)
8888代表該路徑的端口號(hào)
舉個(gè)栗子:
(該 URL 會(huì)調(diào)起車輛詳情頁(yè)):uumobile://mobile/carDetail?car_id=123456,其中 scheme 為 uumobile豌骏,host 為 mobile龟梦,relativePath 為 /carDetail,query 為 car_id=123456窃躲。

在什么場(chǎng)景使用计贰?

下面介紹一下本人曾經(jīng)常用的場(chǎng)景:

其他應(yīng)用想要調(diào)用你APP的某個(gè)頁(yè)面
自己的H5頁(yè)面想要調(diào)用native的某個(gè)頁(yè)面
服務(wù)器下發(fā)路徑,客戶端根據(jù)服務(wù)器下發(fā)跳轉(zhuǎn)路徑跳轉(zhuǎn)相應(yīng)的頁(yè)面
APP端收到服務(wù)器端下發(fā)的PUSH通知欄消息蒂窒,根據(jù)消息的點(diǎn)擊跳轉(zhuǎn)路徑跳轉(zhuǎn)相關(guān)頁(yè)面
這樣說(shuō)大家沒(méi)有在具體業(yè)務(wù)中使用可能不是很清楚躁倒,那么舉個(gè)例子:
我們進(jìn)入到h5的活動(dòng)頁(yè)面荞怒,這時(shí)候點(diǎn)擊某個(gè)鏈接,要求跳回我們的native秧秉,那么就用到了scheme褐桌。

scheme的使用

使用起來(lái)還是非常簡(jiǎn)單的:

1.在Androidmanifest.xml中定義scheme

<activity android:name=".ProcessActivity">

<!-- 要想在別的App上能成功調(diào)起App,必須添加intent過(guò)濾器 -->
<intent-filter>
    <!-- 協(xié)議部分象迎,名字隨便設(shè)置 -->
    <data
        android:host="open.app.example"
        android:scheme="external" />
    <!-- 下面這幾行也必須得設(shè)置 -->
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <action android:name="android.intent.action.VIEW" />
</intent-filter>

</activity>

??:切記 Android 小寫(xiě) 荧嵌。

2.獲取Scheme跳轉(zhuǎn)的參數(shù)

private static final String TAG = ProcessActivity.class.getSimpleName().toString();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_process);

    distribute();
}

private void distribute() {
    Uri uri = getIntent().getData();
    if (uri != null) {

        //url部分
        Log.e(TAG, "uri -----> " + uri);

        // scheme部分
        String scheme = uri.getScheme();
        Log.e(TAG, "scheme -----> " + scheme);

        // host部分
        String host = uri.getHost();
        Log.e(TAG, "host -----> " + host);

        // 訪問(wèn)路勁
        String path = uri.getPath();
        Log.e(TAG, "path -----> " + path);

        // Query部分
        String query = uri.getQuery();
        Log.e(TAG, "query -----> " + query);

        //獲取指定參數(shù)值
        String isShowSplash = uri.getQueryParameter("isShowSplash");
        Log.e(TAG, "isShowSplash -----> " + isShowSplash);

        String infomation = uri.getQueryParameter("infomation");
        Log.e(TAG, "infomation -----> " + infomation);

    } else {
        finish();
    }
}

3.使用

只需要調(diào)用如下代碼就可以:

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("external://open.app.example/first?isShowSplash=true&infomation='我是攜帶的信息'")));
1
1
4.效果展示

讓我們看一下打印出來(lái)的log日志:

圖。砾淌。啦撮。。拇舀。

這是我們接收到的uri傳遞的相關(guān)信息逻族,只打印了一部分不是全部,有興趣大家可以自行打印更多信息骄崩。

實(shí)戰(zhàn)演示

接下來(lái)我們完成一個(gè)小DEMO聘鳞,主要功能通過(guò)外部APP打開(kāi)對(duì)應(yīng)的Activity并傳遞相關(guān)數(shù)據(jù)。
我們先看一下ExternalOpen這個(gè)工程里面最主要的就是配置了scheme能夠通過(guò)uri的方式被啟動(dòng)要拂。

看下目錄結(jié)構(gòu):

這里寫(xiě)圖片描述

功能清單文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="externalopen.libin.com.externalopen">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:launchMode="singleTop"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme.NoActionBar">

    <activity
        android:name="MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".FirstActivity" />
    <activity android:name=".SecondActivity" />
    <activity android:name=".ThirdActivity" />
    <activity android:name=".ProcessActivity">
        <!-- 要想在別的App上能成功調(diào)起App抠璃,必須添加intent過(guò)濾器 -->
        <intent-filter>
            <!-- 協(xié)議部分,名字隨便設(shè)置 -->
            <data
                android:host="open.app.example"
                android:scheme="external" />
            <!-- 下面這幾行也必須得設(shè)置 -->
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <action android:name="android.intent.action.VIEW" />
        </intent-filter>
    </activity>
</application>

</manifest>

這里包含一個(gè)負(fù)責(zé)跳轉(zhuǎn)的ProcessActivity和四個(gè)等候演示用到的展示的Activity界面脱惰。

我們先預(yù)覽一下效果:
這里寫(xiě)圖片描述

可能只看效果圖搏嗡,可能會(huì)看的很迷茫,接下來(lái)看下講解拉一。

首先我們安裝兩個(gè)app采盒,一個(gè)專門負(fù)責(zé)啟動(dòng)相應(yīng)的activity的OmnipotentFrame工程,另外一個(gè)是我們的主角ExternalOpen工程蔚润。

首先我們看到有的會(huì)顯示歡迎界面磅氨,有的不顯示,都是根據(jù)isShowSplash控制嫡纠。
我們?cè)趇sShowSplash=true 顯示歡迎界面烦租,,在isShowSplash=false時(shí)不現(xiàn)實(shí)歡迎界面除盏。

然后具體跳轉(zhuǎn)哪一個(gè)Activity根據(jù)path決定叉橱,然后傳遞的信息內(nèi)容放在information里面。
我們看到我們通過(guò)OmnipotentFrame可以開(kāi)啟ExternalOpen里面的任意activity者蠕。
主要是通過(guò)scheme和自定義processActivity控制的窃祝。

除了在外部app可以打開(kāi),在內(nèi)部也可以使用這個(gè)方法踱侣,同樣H5頁(yè)面也可锌杀,這樣APP之間的交互就方便多了甩栈,不過(guò)具體的還是要和業(yè)務(wù)相關(guān)聯(lián)
更多參數(shù)可以自己根據(jù)業(yè)務(wù)來(lái)定,這里只是給大家一個(gè)啟發(fā)糕再。

負(fù)責(zé)分發(fā)跳轉(zhuǎn)的activity

/**

  • 負(fù)責(zé)分發(fā)跳轉(zhuǎn)的activity
    */

public class ProcessActivity extends AppCompatActivity {

private static final String TAG = ProcessActivity.class.getSimpleName().toString();
public static final String FIRST = "/first";
public static final String SECOND = "/second";
public static final String THIRD = "/third";
public static final String URI = "uri";
public static final String ISSHOWSPLASH = "isShowSplash";
public static final String INFOMATION = "infomation";

private ImageView iv_bg;

String path;
Uri uri;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_process);

    iv_bg = (ImageView) findViewById(R.id.iv_bg);

    try {
        distribute();
    } catch (Exception e) {
        Log.e(TAG, "分發(fā)異常");
    }

}

private void distribute() {
    uri = getIntent().getData();
    if (uri != null) {

        //url部分
        Log.e(TAG, "uri -----> " + uri);

        // scheme部分
        String scheme = uri.getScheme();
        Log.e(TAG, "scheme -----> " + scheme);

        // host部分
        String host = uri.getHost();
        Log.e(TAG, "host -----> " + host);

        // 訪問(wèn)路勁
        path = uri.getPath();
        Log.e(TAG, "path -----> " + path);

        // Query部分
        String query = uri.getQuery();
        Log.e(TAG, "query -----> " + query);

        //獲取指定參數(shù)值
        String isShowSplash = uri.getQueryParameter(ISSHOWSPLASH);
        Log.e(TAG, "isShowSplash -----> " + isShowSplash);

        String infomation = uri.getQueryParameter(INFOMATION);
        Log.e(TAG, "infomation -----> " + infomation);

        //===============================以上為log信息方便理解==============================>


        if (path != null && !path.isEmpty()) {

            /**
             *  是否展示歡迎頁(yè)面
             *  很多情況下從外部開(kāi)啟APP需要展示廣告或者歡迎頁(yè)面量没,這里模擬下一歡迎頁(yè)
             */
            if (isShowSplash.equals("true")) {
                iv_bg.setVisibility(View.VISIBLE);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        iv_bg.setVisibility(View.INVISIBLE);
                        controlActivity(path, uri);
                        finish();
                    }
                },2000);
            }else {
                controlActivity(path, uri);
                finish();
            }

        }

    } else {
        finish();
    }
}

/**
 * 根據(jù)Path確定開(kāi)啟哪個(gè)Activity
 * @param path
 * @param uri
 */
private void controlActivity(String path, Uri uri) {

    if (path.equals(FIRST)) {
        Intent intent = new Intent(this, FirstActivity.class);
        intent.putExtra(INFOMATION, uri.getQueryParameter(INFOMATION));
        startActivity(intent);
    } else if (path.equals(SECOND)) {
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra(INFOMATION, uri.getQueryParameter(INFOMATION));
        intent.putExtra(URI, uri);
        startActivity(intent);
    } else if (path.equals(THIRD)) {
        Intent intent = new Intent(this, ThirdActivity.class);
        intent.putExtra(INFOMATION, uri.getQueryParameter(INFOMATION));
        intent.putExtra(URI, uri);
        startActivity(intent);
    }

}

使用

btn_1.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("external://open.app.example/first?isShowSplash=true&infomation=Path---->FirstActivity******isShowSplash---->true")));

        }
    });
    btn_2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("external://open.app.example/second?isShowSplash=false&infomation=Path---->SecondActivity******isShowSplash---->false")));

        }
    });
    btn_3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("external://open.app.example/third?isShowSplash=true&infomation=Path---->ThirdActivity******isShowSplash---->true")));

        }
    });
    btn_4.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("external://open.app.example/home?isShowSplash=true&infomation=首頁(yè)")));

        }
    });

在需要使用的地方只需要添加uri即可。

這里方便演示只進(jìn)行了外部APP進(jìn)行調(diào)轉(zhuǎn)突想,更多如h5跳轉(zhuǎn)童鞋們可以自行驗(yàn)證殴蹄。
注:原文地址:http://blog.csdn.net/github_33304260/article/details/73194544

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市猾担,隨后出現(xiàn)的幾起案子袭灯,更是在濱河造成了極大的恐慌,老刑警劉巖绑嘹,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稽荧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡工腋,警方通過(guò)查閱死者的電腦和手機(jī)姨丈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)擅腰,“玉大人蟋恬,你說(shuō)我怎么就攤上這事〕酶裕” “怎么了歼争?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)渗勘。 經(jīng)常有香客問(wèn)我沐绒,道長(zhǎng),這世上最難降的妖魔是什么旺坠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任乔遮,我火速辦了婚禮,結(jié)果婚禮上价淌,老公的妹妹穿的比我還像新娘申眼。我一直安慰自己瞒津,他們只是感情好蝉衣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著巷蚪,像睡著了一般病毡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屁柏,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天啦膜,我揣著相機(jī)與錄音有送,去河邊找鬼。 笑死僧家,一個(gè)胖子當(dāng)著我的面吹牛雀摘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播八拱,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼阵赠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了肌稻?” 一聲冷哼從身側(cè)響起清蚀,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爹谭,沒(méi)想到半個(gè)月后枷邪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诺凡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年东揣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绑洛。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡救斑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出真屯,到底是詐尸還是另有隱情脸候,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布绑蔫,位于F島的核電站运沦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏配深。R本人自食惡果不足惜携添,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篓叶。 院中可真熱鬧烈掠,春花似錦、人聲如沸缸托。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)俐镐。三九已至矫限,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叼风。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工取董, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人无宿。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓茵汰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親孽鸡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子经窖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,501評(píng)論 25 707
  • 哎呀呀 ,馬上就要面臨找工作了,媛媛心里緊張呀. 作為一個(gè)即將畢業(yè)的Android程序媛,開(kāi)始面臨找工作了,...
    仇諾伊閱讀 4,535評(píng)論 7 59
  • 最近剛從舊公司離職,為面試在做準(zhǔn)備梭灿,因?yàn)槠綍r(shí)開(kāi)發(fā)CV大法用得比較多画侣,很多基礎(chǔ)知識(shí)掌握得不是很牢靠以及很多工具框架只...
    黎清海閱讀 2,171評(píng)論 1 19
  • 1.什么是Activity?問(wèn)的不太多配乱,說(shuō)點(diǎn)有深度的 四大組件之一,一般的,一個(gè)用戶交互界面對(duì)應(yīng)一個(gè)activit...
    JoonyLee閱讀 5,728評(píng)論 2 51
  • 八月桂花八月開(kāi),花香悄悄迎面來(lái)皮迟。 雖然偏居墻角旁搬泥,傲氣長(zhǎng)存如依然。 拍攝于北京植物園盆景園南側(cè)一角落的一株桂花樹(shù)伏尼。
    退休人老高閱讀 447評(píng)論 0 1