直接上干货:
PackageManager pm = mContext.getPackageManager(); PackageInfo pi = pm.getPackageArchiveInfo(mFilename, 0); mNewResources = pm.getResourcesForApplication(pi.applicationInfo);
要获取插件的资源信息我们采用的是通过实例packageInfo,并动态的更改里边的sourceDir和publicSourceDir为插件Apk路径地址。
而这里关键的是什么时候去加载的资源信息呢:
1,pm.getPackageArchiveInfo
public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) { PackageParser packageParser = new PackageParser(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); final File sourceFile = new File(archiveFilePath); PackageParser.Package pkg = packageParser.parsePackage( sourceFile, archiveFilePath, metrics, 0); if (pkg == null) { return null; } if ((flags & GET_SIGNATURES) != 0) { packageParser.collectCertificates(pkg, 0); } PackageUserState state = new PackageUserState(); return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state); }
如图,在执行取packageArchiveInfo的时候,回去解析包文件,具体看源码:
493 public Package parsePackage(File sourceFile, String destCodePath, 494 DisplayMetrics metrics, int flags) { 495 mParseError = PackageManager.INSTALL_SUCCEEDED; 496 497 mArchiveSourcePath = sourceFile.getPath(); 498 if (!sourceFile.isFile()) { 499 Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath); 500 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 501 return null; 502 } 503 if (!isPackageFilename(sourceFile.getName()) 504 && (flags&PARSE_MUST_BE_APK) != 0) { 505 if ((flags&PARSE_IS_SYSTEM) == 0) { 506 // We expect to have non-.apk files in the system dir, 507 // so don't warn about them. 508 Slog.w(TAG, "Skipping non-package file: " + mArchiveSourcePath); 509 } 510 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 511 return null; 512 } 513 514 if (DEBUG_JAR) 515 Slog.d(TAG, "Scanning package: " + mArchiveSourcePath); 516 517 XmlResourceParser parser = null; 518 AssetManager assmgr = null; 519 Resources res = null; 520 boolean assetError = true; 521 try { 522 assmgr = new AssetManager(); 523 int cookie = assmgr.addAssetPath(mArchiveSourcePath); 524 if (cookie != 0) { 525 res = new Resources(assmgr, metrics, null); 526 assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 527 Build.VERSION.RESOURCES_SDK_INT); 528 parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 529 assetError = false; 530 } else { 531 Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); 532 } 533 } catch (Exception e) { 534 Slog.w(TAG, "Unable to read AndroidManifest.xml of " 535 + mArchiveSourcePath, e); 536 } 537 if (assetError) { 538 if (assmgr != null) assmgr.close(); 539 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 540 return null; 541 } 542 String[] errorText = new String[1]; 543 Package pkg = null; 544 Exception errorException = null; 545 try { 546 // XXXX todo: need to figure out correct configuration. 547 pkg = parsePackage(res, parser, flags, errorText); 548 } catch (Exception e) { 549 errorException = e; 550 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 551 } 552 553 554 if (pkg == null) { 555 // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED 556 // just means to skip this app so don't make a fuss about it. 557 if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) { 558 if (errorException != null) { 559 Slog.w(TAG, mArchiveSourcePath, errorException); 560 } else { 561 Slog.w(TAG, mArchiveSourcePath + " (at " 562 + parser.getPositionDescription() 563 + "): " + errorText[0]); 564 } 565 if (mParseError == PackageManager.INSTALL_SUCCEEDED) { 566 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 567 } 568 } 569 parser.close(); 570 assmgr.close(); 571 return null; 572 } 573 574 parser.close(); 575 assmgr.close(); 576 577 // Set code and resource paths 578 pkg.mPath = destCodePath; 579 pkg.mScanPath = mArchiveSourcePath; 580 //pkg.applicationInfo.sourceDir = destCodePath; 581 //pkg.applicationInfo.publicSourceDir = destRes; 582 pkg.mSignatures = null; 583 584 return pkg; 585 }过程中实例了AssetManager 和Resources
这样在后边调用的时候无论是实例新的ContextThemeWrapper,还是取用资源对象都可以通过getResources()拿到,供动态加载插件资源所用。