隱式 Intent 已經(jīng)不是你以為的 Intent 了
一、前言
如果你的 App 內(nèi),有使用到隱式 Intent 去與其他 App 交互。例如,分享一個(gè)鏈接,當(dāng)你的系統(tǒng)升級(jí)到 Android M(Api level 23) 之后,你就需要小心了,它可能并不能按照你的意愿去執(zhí)行你想執(zhí)行的任務(wù)。
舉個(gè)例子,你想分享一個(gè)鏈接,而每次都想讓用戶主動(dòng)去選擇一個(gè),但是有時(shí)候這個(gè)操作并不能如愿,如果用戶主動(dòng)指定了某個(gè) App 打開這個(gè) 鏈接,你的 App 將直接使用用戶指定的 App 打開這個(gè)鏈接(其實(shí)是有例外情況的,后面說)。
二、Android M 改變了什么
一般我們想要分享一個(gè)鏈接出去,直接使用 隱式 Intent 即可。
在 Android M 之下,它會(huì)調(diào)起系統(tǒng)內(nèi),所有符合的 App 供用戶選擇一個(gè)合適的去打開。
可以看到,默認(rèn)會(huì)彈出一個(gè)選擇器,讓用戶選擇一個(gè) App 來處理。這沒什么好說的,是一個(gè)常規(guī)的操作,應(yīng)該幾乎所有的 Android 開發(fā)人員,都是不陌生的。
除了這個(gè)系統(tǒng)的選擇器,我們也是可以在代碼中,去查詢到符合 Intent 過濾要求的 App 的。需要使用 PackagemManager.queryIntentActivitys() 方法來進(jìn)行查詢,上面的 demo 中,也通過 Log 打印出了它的輸出。
看輸出,和我們選擇器中的是一致的。
但是,這一切在 Android M 就開始改變了。
Android M 推出了 App Links 是的概念,系統(tǒng)將通過你的配置的網(wǎng)址進(jìn)行身份驗(yàn)證,如果通過驗(yàn)證,你需要打開的鏈接,將直接使用你的 App 來打開,而不是直接跳轉(zhuǎn)到一個(gè)瀏覽器,這個(gè)過程是不會(huì)向用戶詢問的。但是 App Links 依托于 Google 的服務(wù),所以國內(nèi)開發(fā)者應(yīng)該享受不到它的便利。
但是處理通過網(wǎng)站的服務(wù)器來進(jìn)行身份驗(yàn)證之外,還可以在設(shè)置頁面中,對(duì)默認(rèn)的程序進(jìn)行設(shè)定。
路徑是:系統(tǒng)設(shè)置 → 應(yīng)用 → 應(yīng)用程序 → 默認(rèn)打開
例如這里打開了 Google + 這款 App 的默認(rèn)打開頁面。
可以在『打開支持的鏈接』中,選擇是否默認(rèn)打開使用它來完成打開鏈接的操作。
一旦選擇了『在此應(yīng)用中打開』,在去運(yùn)行上面的程序,你將直接使用 Google+ 打開你的鏈接,而用戶將失去選擇的權(quán)利,除非用戶將這里重新設(shè)置為『每次都詢問』。
三、例外情況
實(shí)際上,這也是存在例外的情況的。
3.1 過濾會(huì)先校驗(yàn) domain
下面是一個(gè)標(biāo)準(zhǔn)的 URL 格式:
scheme://host.domain:port/path
這種隱式 Intent ,優(yōu)先考慮能與 domain 匹配的 App,這是系統(tǒng)內(nèi)部的一個(gè)優(yōu)先級(jí)策略。
例如,現(xiàn)在在我的系統(tǒng)中,有一款 HiitTime 的 App,它設(shè)定了一個(gè) m.hiittime.com 的鏈接支持。
再修改前面提供的 Demo,只是把鏈接指向了它。
這樣的情況下,哪怕我們也將 Google+ 設(shè)置為『在此應(yīng)用內(nèi)打開』,它最終也是允許用戶去選擇 HttiTime 這個(gè) App 來處理的。
3.2 系統(tǒng) App 優(yōu)先級(jí)高
前面 HiitTime 的例子可以看到,實(shí)際上我是沒有指定 Chrome 來處理的,但是選擇器中,實(shí)際上是會(huì)有 Chrome 的選擇的,這個(gè)我暫時(shí)沒有發(fā)現(xiàn)可以去掉它的辦法。
而在 Chrome 的默認(rèn)開打的選擇頁面中,也是無法操作的,我只能理解為它對(duì)系統(tǒng) App 做了特殊的保護(hù)處理。
四、辟謠
之前看到有人說可以在對(duì) Intent 的 Uri 只設(shè)定 scheme ,例如,’http://‘ 然后后面什么都不跟,這樣系統(tǒng)就會(huì)列出所有的瀏覽器供你選擇,然后我們就可以在選擇列表中,手動(dòng)指定打開的 App ,這樣就可以很好的打開它了。
但是實(shí)測(cè),這樣是行不通的,當(dāng)設(shè)置了 Google+ 『在此應(yīng)用內(nèi)打開』的情況下,依然會(huì)直接使用 Google+ 來完成我們的操作,所以這個(gè)操作是不成立的。
但是也提供了另外的一個(gè)思路,我們實(shí)際上是可以通過 PackageManager 拿到系統(tǒng)中安裝的 App 的,而通常我們需要分享打開的 App 就那么多,所以我們可以以窮舉的方式,篩選出需要的 App ,自己來定義這個(gè)選擇器,然后指定對(duì) Intent 指定 PackageName 就可以完成對(duì)指定 App 的分享,而繞過『在此應(yīng)用內(nèi)打開』的設(shè)定。
這只是一個(gè)思路,沒有實(shí)際實(shí)驗(yàn),但是應(yīng)該可行。
五、小結(jié)
如果你的 App 內(nèi),有這種隱式的操作,就應(yīng)該檢查一下是否在這樣的情況下,依然能完成我們?nèi)缙诘墓δ堋?/p>
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過微信公眾號(hào)聯(lián)系作者獲取授權(quán)】