精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Android 下 FileProvider 的 authorities 重名會怎么樣?

移動開發 Android
如果有兩個或多個 FileProvider 的 authorities 重名,那么只有合并后的 AndroidManifest.xml 文件里,排在最前面的那個配置會生效。

先說結論:如果有兩個或多個 FileProvider 的 authorities 重名,那么只有合并后的 AndroidManifest.xml 文件里,排在最前面的那個配置會生效。

一、場景

應用里有個自升級的功能,下載完 apk 后,通過 FileProvider 提供 Uri 進行安裝。我修改了文件下載路徑后,功能失效了,報錯如下:

java.lang.IllegalArgumentException: Failed to find configured root that contains /data/user/0/org.mazhuang.test/cache/download/xxx.apk
    at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:738)
    at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:417)

對應的 provider 的聲明是:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

provider_paths 內容:

<?xml version="1.0" encoding="utf-8"?>
<paths >
    <cache-path name="internal_cache_download" path="download/" />
</paths>

二、分析

對照 FileProvider 官方文檔:https://developer.android.com/reference/android/support/v4/content/FileProvider.html ,我再三確認了配置本身沒有問題。

然后在報錯堆棧的 android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile 方法處下斷點調試:

@Override
public Uri getUriForFile(File file) {
    // some code here
    // Find the most-specific root path
    Map.Entry<String, File> mostSpecific = null;
    for (Map.Entry<String, File> root : mRoots.entrySet()) {
        final String rootPath = root.getValue().getPath();
        if (path.startsWith(rootPath) && (mostSpecific == null
                || rootPath.length() > mostSpecific.getValue().getPath().length())) {
            mostSpecific = root;
        }
    }

    if (mostSpecific == null) {
        throw new IllegalArgumentException(
                "Failed to find configured root that contains " + path);
    }
    // some code here
}

發現 SimplePathStrategy 的 mRoots 里確實沒有我配置的路徑。而 SimplePathStrategy 唯一的構造方法的參數是 authority,該實例的 authority 確實是 ${applicationId}.provider 無誤……那么,合理猜測,是有同名的 FileProvider,這里用到的是另一個 FileProvider 的 mRoots。

為了驗證該猜測,我從兩方面做確認:

  • 查看合并后的 AndroidManifest.xml 文件,是否有其它 FileProvider 的 authorities 也是 ${applicationId}.provider?
  • 閱讀 Android Frameworks 里的相關源碼,確認解析 provider 配置、取 FileProvider 實例的邏輯。

1.查看合并后的 AndroidManifest.xml

現在 Android Studio 已經提供了非常方便的查看合并后的 AndroidManifest.xml 的功能,打開 app 項目的 AndroidMenifest.xml 文件,在編輯器底部有個 Merged Manifest 選項卡,點擊即可查看。

可以看到,確實有兩個 FileProvider 的 authorities 都是 ${applicationId}.provider,另一個是從一個第三方庫里來的,并且,它排在前面。

2.源碼確認

首先是在 Android Studio 里進行,找到調用 SimplePathStrategy 構造方法的地方,是在 android.support.v4.content.FileProvider#parsePathStrategy:

/**
 * Parse and return {@link PathStrategy} for given authority as defined in
 * {@link #META_DATA_FILE_PROVIDER_PATHS} {@code <meta-data>}.
 *
 * @see #getPathStrategy(Context, String)
 */
private static PathStrategy parsePathStrategy(Context context, String authority)
        throws IOException, XmlPullParserException {
    final SimplePathStrategy strat = new SimplePathStrategy(authority);

    final ProviderInfo info = context.getPackageManager()
            .resolveContentProvider(authority, PackageManager.GET_META_DATA);
    // some code here
}

這里的 context.getPackageManager().resolveContentProvider 的實現,一路通過以下路徑找到:

// android.app.ContextImpl#getPackageManager
// -->
// android.app.ActivityThread#getPackageManager
public static IPackageManager getPackageManager() {
    if (sPackageManager != null) {
        return sPackageManager;
    }
    IBinder b = ServiceManager.getService("package");
    sPackageManager = IPackageManager.Stub.asInterface(b);
    return sPackageManager;
}

到這里動用一點歷史經驗,可知實際實現類是 PackageManagerService,來看看 PackageManagerService#resolveContentProvider 的實現:

@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
    if (!sUserManager.exists(userId)) return null;
    flags = updateFlagsForComponent(flags, userId, name);
    final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
    // reader
    synchronized (mPackages) {
        final PackageParser.Provider provider = mProvidersByAuthority.get(name);
        // some code here
    }
    // some code here
}

在 PackageManagerService 里繼續查找寫入 mProvidersByAuthority 的地方,在 PackageManagerService#commitPackageSettings:

/**
 * Adds a scanned package to the system. When this method is finished, the package will
 * be available for query, resolution, etc...
 */
private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
        UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
    // some code here
    synchronized (mPackages) {
        // some code here
        for (i=0; i<N; i++) {
            PackageParser.Provider p = pkg.providers.get(i);
            p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                    p.info.processName);
            mProviders.addProvider(p);
            p.syncable = p.info.isSyncable;
            if (p.info.authority != null) {
                String names[] = p.info.authority.split(";");
                p.info.authority = null;
                for (int j = 0; j < names.length; j++) {
                    // some code here
                    // 【我們要找的地方】
                    if (!mProvidersByAuthority.containsKey(names[j])) {
                        mProvidersByAuthority.put(names[j], p);
                        if (p.info.authority == null) {
                            p.info.authority = names[j];
                        } else {
                            p.info.authority = p.info.authority + ";" + names[j];
                        }
                        // some code here

從上面這段中我們可以得到兩個知識點:

  • 如果已經有同名的 authority,那么后面的 Provider 配置會被忽略掉;
  • authority 可以配置多個,用分號分隔。(這一點在官方文檔之類的都沒有找到說明,也許官方覺得配置項的名稱 autorities 就說明了一切?實測可正常使用。)

接下來還有一點需要確認的,就是 pkg.providers 是否是按 AndroidManifexs.xml 里的順序排列的。

根據上面代碼里的線索,可以留意到 PackageParser 類,按如下順序遞進:

// android.content.pm.PackageParser#parseBaseApk(java.io.File, android.content.res.AssetManager, int)
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
        throws PackageParserException {
        // some code here
        // 下面這行里的 ANDROID_MANIFEST_FILENAME = AndroidManifest.xml
        parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

        final String[] outError = new String[1];
        final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
        // some code here
}

// --> 
// android.content.pm.PackageParser#parseBaseApk(java.lang.String, android.content.res.Resources, android.content.res.XmlResourceParser, int, java.lang.String[])
// -->
// android.content.pm.PackageParser#parseBaseApkCommon
// -->
// android.content.pm.PackageParser#parseBaseApplication
// -->
private boolean parseBaseApplication(Package owner, Resources res,
        XmlResourceParser parser, int flags, String[] outError)
    // some code here
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }

        String tagName = parser.getName();
        if (tagName.equals("activity")) {
            // some code here
        } else if (tagName.equals("provider")) {
            Provider p = parseProvider(owner, res, parser, flags, outError);
            if (p == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.providers.add(p);
        // some code here

至此,我們已經可以確定 pkg.providers 是按 AndroidManifest.xml 里的順序解析出來的了。

三、解決方案

既然已經知道了問題的原因,那么解決方案也就呼之欲出了:

修改自己的 FileProvider 的 authorities,不會和其它庫的 authorities 重名即可。

四、小結


源碼面前,了無秘密。——侯捷


如果遇到疑難問題,而恰好又有源碼可查,那么就不要猶豫,直接去看源碼吧!花一些時間和耐心,最終會找到你想要的。

責任編輯:趙寧寧 來源: 悶騷的程序員
相關推薦

2023-06-30 08:23:36

Spring!SolonJavalin

2024-08-22 08:50:51

2025-02-11 09:01:57

2018-07-31 15:38:07

SDN物聯網IIoT

2020-02-11 16:35:23

疫情B類拐點

2021-09-01 10:50:21

int main()return 0語言

2021-07-06 07:27:44

函數Return編譯器

2014-02-18 11:24:07

云計算PaaS

2024-10-14 09:58:06

并發編程共享

2020-04-28 08:10:42

編程Resflux應用

2018-08-07 09:38:06

2025-07-29 10:00:02

2024-05-07 08:46:06

GoGoogle云原生

2020-05-11 17:08:28

蘋果WindowsMacBook

2020-05-06 08:44:20

等保2.0WAFIDC

2015-07-23 11:49:31

程序猿

2020-11-27 07:45:31

JVM垃圾回收

2019-07-19 15:42:57

Hadoop大數據YuniKorn

2023-05-15 10:17:03

2009-12-24 14:05:06

Fedora core
點贊
收藏

51CTO技術棧公眾號

狠狠狠色丁香婷婷综合久久五月| 久久亚洲成人| 色婷婷av一区二区| 亚洲欧洲另类精品久久综合| 国产ts变态重口人妖hd| 夜夜精品视频| 中文字幕日韩欧美精品在线观看| 青青草原播放器| 欧美美女日韩| 一区二区三区四区在线播放| 热re99久久精品国99热蜜月| 国产不卡精品视频| 日韩高清不卡一区| 97在线视频免费观看| 3d动漫精品啪啪一区二区下载| 亚洲欧美专区| 一本久道久久综合中文字幕| 日本人妻伦在线中文字幕| www在线免费观看| 成人v精品蜜桃久久一区| 国产欧美中文字幕| 成人在线免费看视频| 欧美三级特黄| 色悠悠久久久久| 91精品人妻一区二区| 哺乳挤奶一区二区三区免费看| 色综合天天综合| 九色自拍视频在线观看| 亚洲综合影视| 综合色天天鬼久久鬼色| 日韩电影在线播放| 亚洲日本国产精品| 成人国产精品免费网站| 亚洲一区二区三区乱码aⅴ蜜桃女| 四虎影院在线免费播放| 亚洲免费中文| 992tv成人免费视频| 清纯粉嫩极品夜夜嗨av| 最新欧美人z0oozo0| 日韩中文理论片| 五月天综合视频| 亚洲va久久久噜噜噜久久| 亚洲高清久久网| youjizz.com国产| 一区二区三区亚洲变态调教大结局 | 精品一区二区三区av| 国产97在线播放| 男人天堂2024| 久久综合亚州| 国产成人精品免费久久久久| 视频一区二区三区四区五区| 亚洲女同同性videoxma| 18一19gay欧美视频网站| 日本五十熟hd丰满| 夜久久久久久| 日韩免费在线播放| 天天综合久久综合| 男人的天堂久久精品| 国产精品久久一| 亚洲一线在线观看| 国内一区二区在线| 97超级碰碰| 亚洲va天堂va欧美ⅴa在线| 丰满放荡岳乱妇91ww| 国产精品久久久久久久久婷婷| 黄色美女一级片| 91麻豆精品在线观看| 日韩jizzz| 欧美videos极品另类| 亚洲色图一区二区三区| 青青青青在线视频| 亚洲美女久久精品| 欧美撒尿777hd撒尿| 毛毛毛毛毛毛毛片123| 国产精品欧美大片| 亚洲欧美日韩一区二区三区在线| 摸摸摸bbb毛毛毛片| 91视频一区| 欧美高清在线视频观看不卡| 国产一级精品视频| 蜜臀av一级做a爰片久久| 92裸体在线视频网站| 欧美77777| 国产日产欧美一区二区三区| www.午夜色| 成人女同在线观看| 欧美视频完全免费看| 麻豆免费在线观看视频| 免费看成人哺乳视频网站| 深夜福利一区二区| 九九九国产视频| 日本在线不卡视频| 国产传媒一区二区三区| 黄网在线观看| 一区二区激情小说| wwwwww.色| 澳门精品久久国产| 中文字幕在线日韩 | 久久天堂精品| 91久久国产综合久久蜜月精品 | 国产片一区二区| 亚洲av首页在线| 欧美色网一区| 欧美xxxxx牲另类人与| av网站免费在线看| 亚洲欧洲视频| 亚洲影院色无极综合| 欧美日韩国产亚洲沙发| 亚洲一区在线观看视频| 天天爽人人爽夜夜爽| 久久精品福利| 美乳少妇欧美精品| 一级成人免费视频| 国产亚洲精品福利| 无码人妻丰满熟妇区96| 久久久久久亚洲精品美女| 中文字幕av一区二区| 精品欧美一区二区三区免费观看 | 免费精品99久久国产综合精品| 成人免费看片网站| 色影院视频在线| 欧美性色19p| 少妇精品无码一区二区三区| 欧美日韩mv| 91免费在线视频| 在线观看免费版| 欧美中文字幕久久| 久久久久久久久久久久久久久| 一本色道久久综合亚洲精品不卡| 91大片在线观看| 黄页视频在线播放| 欧美美女网站色| 日韩av片在线免费观看| 久久久夜夜夜| 欧美日韩系列| 亚洲国产欧美日本视频| 亚洲欧美国产va在线影院| 国产欧美日韩另类| 成人av在线一区二区三区| 欧美黑人在线观看| 豆花视频一区二区| 久久久久久久久久久久av| 国产福利免费视频| 一区二区视频在线| 免费啪视频在线观看| 国产精品草草| 国产精品一区二区三区在线 | 91精品在线观看国产| 国产在线久久久| 成人在线视频亚洲| 日韩视频免费观看高清完整版在线观看 | 婷婷丁香一区二区三区| 亚洲成a人片综合在线| aaa黄色大片| 一本综合久久| 日本在线播放不卡| 欧美黄页在线免费观看| 久久精品国产亚洲精品2020| 国产美女免费视频| 樱花草国产18久久久久| 精品人妻在线视频| 欧美亚洲一区| 亚洲v国产v| а天堂中文最新一区二区三区| 欧美不卡视频一区发布| 丰满熟妇乱又伦| 一本色道久久综合亚洲aⅴ蜜桃| 人妻aⅴ无码一区二区三区| 久久黄色影院| 中文字幕av日韩精品| 中文一区二区三区四区| 91av视频导航| 成人在线视频成人| 日韩一区二区中文字幕| 日韩三级视频在线播放| 久久久久成人黄色影片| 亚洲一二三av| 99国产精品视频免费观看一公开| 日本精品一区| 国产精品亚洲一区二区在线观看 | 欧美日韩a v| 国产精品国产三级国产aⅴ入口 | 亚洲天天综合网| 亚洲欧美激情在线| 成年人网站免费在线观看| 青青草国产成人99久久| 成人免费看片'免费看| 中文字幕精品影院| 91黄色精品| 亚洲人免费短视频| 欧美成人自拍视频| 黄色av网址在线免费观看| 91精品国产福利在线观看 | 成人影音在线| 色yeye香蕉凹凸一区二区av| 日本黄色三级视频| 69av一区二区三区| 日韩手机在线视频| 亚洲午夜电影在线观看| 欧美午夜激情影院| 99久久婷婷国产精品综合| 91亚洲精品久久久蜜桃借种| 国产亚洲欧洲| 国产高清不卡无码视频| 欧美色蜜桃97| 久久精品人人做人人爽电影| 白嫩亚洲一区二区三区| 国产精品视频区| 性国裸体高清亚洲| 久久久久久午夜| 成人在线影视| xvideos亚洲| 黄上黄在线观看| 日韩精品免费在线观看| 亚洲第一视频在线| 欧美另类高清zo欧美| 日韩人妻精品中文字幕| 午夜精品久久久久久不卡8050 | 欧美性极品xxxx做受| 国产极品国产极品| 国产精品国产a级| xxxxx在线观看| 97精品国产露脸对白| 国产精品99久久久精品无码| 国产一区二区影院| 国产日韩欧美久久| 天堂av在线一区| 人妻熟女一二三区夜夜爱| 亚洲日韩视频| 国产精品成人久久电影| 欧美视频一区| 轻点好疼好大好爽视频| 国产精品久久| 久草视频这里只有精品| 国精品一区二区| 日韩精品一区二区三区四| 欧美在线视屏| 屁屁影院ccyy国产第一页| 女同性一区二区三区人了人一| 日本丰满少妇黄大片在线观看| 欧美丰满老妇| 一区二区三区四区欧美日韩| 欧美激情另类| 自拍偷拍视频在线| 女人天堂亚洲aⅴ在线观看| 国产日韩第一页| 亚洲精品久久久| 福利在线小视频| 欧美午夜在线视频| 青青草精品视频在线| 国产农村妇女毛片精品久久莱园子| 男人操女人免费软件| 久久精品网址| 五月婷婷之综合激情| 老司机午夜精品| 999热精品视频| 国产成a人无v码亚洲福利| 亚洲一区二区三区黄色| 91麻豆成人久久精品二区三区| 精品少妇人妻一区二区黑料社区 | 中文字幕av久久爽av| 一区2区3区在线看| 日韩免费不卡视频| 日韩欧美中文字幕在线观看| 波多野结衣黄色网址| 欧美日韩一级大片网址| 国产免费久久久| 精品剧情v国产在线观看在线| 欧美在线 | 亚洲| 亚洲天堂第一页| 国产黄a三级三级三级av在线看 | 鲁一鲁一鲁一鲁一澡| 巨乳诱惑日韩免费av| 日本77777| 不卡电影一区二区三区| 国产91丝袜美女在线播放| 亚洲色图制服诱惑| 69视频免费在线观看| 欧美精品成人一区二区三区四区| 亚洲AV无码一区二区三区性| 亚洲美女黄色片| 好吊日视频在线观看| 欧美性视频在线| 亚洲影视资源| 久久综合毛片| 综合激情在线| av动漫免费看| 国产成a人无v码亚洲福利| 手机看片福利视频| 亚洲成人免费在线观看| 亚洲综合成人av| 欧美xxxxx牲另类人与| 3p视频在线观看| 欧美一级视频一区二区| 国产精品免费精品自在线观看| 久久精品一二三区| 亚洲香蕉av| 国产精彩免费视频| 高清在线不卡av| 懂色av粉嫩av浪潮av| 婷婷久久综合九色综合绿巨人| 一二三区中文字幕| 亚洲欧美一区二区三区四区| 色屁屁www国产馆在线观看| 国产精品流白浆视频| 日本三级久久| 男女激情免费视频| 九九国产精品视频| 中文字幕成人动漫| 高跟丝袜欧美一区| 亚洲成人中文字幕在线| 久久综合伊人77777| 视频在线日韩| 蜜桃传媒一区二区| 99国产精品久久久久久久成人热| 美女被爆操网站| 亚洲丝袜精品丝袜在线| 中文字幕在线网站| 亚洲欧美日韩天堂| 亚洲伊人av| 九九九九九九精品| 狠狠综合久久av一区二区老牛| 国产性生活一级片| 国产精品久久久久影院老司| 国产视频1区2区| 日韩精品中文在线观看| 91九色在线播放| 春色成人在线视频| 欧美91大片| 99热这里只有精品2| 综合色中文字幕| 国产欧美一级片| 久久久精品一区二区三区| 粉嫩av一区二区三区四区五区| 欧美一区国产一区| 日韩影院在线观看| 免费看污片网站| 在线观看视频91| jizz日韩| 91久久国产精品| 91精品啪在线观看国产81旧版| 手机免费看av网站| 亚洲人成7777| 国产富婆一级全黄大片| 欧美极品少妇与黑人| 黑色丝袜福利片av久久| 日韩中文字幕在线视频观看| eeuss国产一区二区三区| 日本最新中文字幕| 日韩精品中文字幕在线播放| 午夜影院在线播放| 日本一区高清不卡| 捆绑变态av一区二区三区| a一级免费视频| 91精品国产综合久久久久久漫画 | 一区二区三区高清不卡| 亚洲乱码精品久久久久..| 欧美激情亚洲综合一区| 欧美色图五月天| 三级在线视频观看| 亚洲欧洲一区二区在线播放| 性一交一乱一伧老太| 午夜精品美女自拍福到在线| 宅男在线一区| 欧美日韩中文不卡| 亚洲综合成人网| 日韩精品视频无播放器在线看| 国产成人免费av电影| 亚洲激情五月| 精品国产人妻一区二区三区| 色老头久久综合| а√天堂8资源在线官网| 国外成人在线视频网站| 日韩精品久久理论片| 九九热视频在线免费观看| 精品国产成人系列| 巨胸喷奶水www久久久免费动漫| 少妇高潮大叫好爽喷水| 久久影院电视剧免费观看| 91麻豆成人精品国产| 久久久免费观看视频| 国产区精品区| 精产国品一区二区三区| 日韩欧美国产网站| 国产视频中文字幕在线观看| 国产综合 伊人色| 毛片av一区二区| 日韩女优在线观看| 久久视频中文字幕| 天堂资源在线亚洲| 1314成人网| 91国产丝袜在线播放| 欧美大片黄色| 五月天国产一区| 99精品久久久久久| 精品久久人妻av中文字幕| 国产精品久久久久久久久久| 亚洲日本黄色| 东京热无码av男人的天堂| 亚洲级视频在线观看免费1级|