java apache linux mysql Windows Firefox Ubuntu Android 编程 开源 shell 云计算 centos google wordpress php 程序员 Python 微软 nginx

Android M中Intent的解析

原文鏈接 : Intent Resolving in Android M
原文作者 : Said Tahsin Dane
譯文出自 : 開發技術前線 www.devtf.cn。未經允許,不得轉載!
譯者 : liuling07
校對者: desmond1121
狀態 : 完成

譯文連接:Android M中Intent的解析

註意了!在Android 6.0中,“隱式Intent”的解析不能像之前版本那樣正常工作了。這很有可能導致你的app不能正常使用。

現在讓我解釋一下這個意料之中的問題以及為什麽它不能正常使用: 最近,我正在開發一個小的開源項目,叫做“Open Link With”。希望不久後它能夠在應用市場上架。

我的這個app能夠讓你在其他app之間隨意切換。當你給我分享一個鏈接的時候,我基本上可以根據這個鏈接查詢出所有可以處理這個鏈接的Activity。然後我會模擬一個系統對話框讓你切換app。

从已经打开的youtube的web页面切换到youtube应用从已经打开的youtube的web页面切换到youtube应用

我一直都是使用下面的方法:

List<ResolveInfo> infos = packageManager
        .queryIntentActivities(intent, MATCH_DEFAULT_ONLY);
這段代碼幾乎所有Android開發者都比較熟悉,並且我也相信大部分app都有用到這段代碼。

我的手機裏有兩個瀏覽器。“一個URL是Google+ 的Intent”期望得到一個具有3個ResolveInfo對象的列表(Google+應用以及兩個瀏覽器)。

好吧,並不是這樣!

歡迎來到Android 6.0!

Android 6.0引進了應用關聯。系統主要通過你的web頁面來認證,並且自動使用你的app來打開這些URL,而不會向你做任何請求。或者你可以到系統設置,選擇 “應用程序”,然後點擊一個應用,再點擊“默認打開方式”,然後設置“用這個應用打開”,就可以每次都使用這個應用打開。

Android 6.0的应用默认设置页面Android 6.0的应用默认设置页面

在這種情況下,queryIntentActivities方法只會給開發者返回一個只有一個Activity的列表(此例子返回的是Google+)。

雖然這是在意料之中的,但是應該在文檔中註明,因為它與公共API相矛盾了。

我研究了一下,發現了一個MATCH_ALL標誌,文檔表示,它將禁用所有的系統級過濾器。

/**
 * Querying flag: if set and if the platform is doing any filtering of the results, then
 * the filtering will not happen. This is a synonym for saying that all results should
 * be returned.
 */
public static final int MATCH_ALL = 0x00020000;
這對我來說沒什麽用。我打開源碼(至少我有源碼)並開始研究這個方法。

它似乎優先考慮驗證應用程序的域,不僅在它的內部系統,在公共API中也是如此。

如果有一個驗證應用程序的域,它不會返回任何其他東西。MATCH_ALL標誌會移除一些系統過濾器,但是僅僅是在沒有驗證程序的情況下。

對於這個問題,我找不到任何可變通的措施。它只是排除瀏覽器應用,即使他們的IntentFilters匹配。

之所以沒有可變通的措施,是因為他是一個內部組件(我們無法訪問),Android SDK通過IPC使用AIDL與它進行通信。

大部分開發者使用這個方法來判斷是否至少有一個Activity來處理隱式的Intent。在大多數情況下,列表中第一項就是你想要的。

在花了幾個小時搞明白到底發生了什麽之後,我嘗試尋找一個我認為每個人都應該知道的解決方案。

在Android 6.0中,改動的地方很多。實際上谷歌提供了一些改變清單,在清單中你能看到到底有哪些改變。我認為還有很多類似上面的一些沒有在清單中列出的改變,而這些改動很有可能導致你的應用無法正常運行。

所以如果你使用PackageManager的方法,你一定得小心,並且認真檢查。

延伸阅读

    评论