English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Questo articolo spiega l'installazione di applicazioni APK in Android utilizzando il principio di PackageParser.parserPackage. Condividiamo questo con tutti voi per riferimento, come segue:
Quando Android installa un APK, inizialmente lo analizza, qui ci sono molte cose da fare, una delle quali è analizzare il file Manifest.xml e impacchettare tutti gli elenchi di Manifest degli APK in vari oggetti e conservarli in memoria
La classe di analisi di Manifest è molto importante, si chiama frameworks\base\core\java\android\content\pm\PackageParser
PackageManagerService chiama il metodo parserPackage di PackageParser per analizzare l'elenco APK, iniziamo ad analizzare l'implementazione di PackageParser:
PackageParser utilizza lo strumento XMLPullParser per analizzare XML, quindi lo impacchetta rispettivamente attraverso vari classi xxxInfo di android.content.pm:
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { //Ultimo messaggio di errore di analisi da eseguire mParseError = PackageManager.INSTALL_SUCCEEDED; //Ottiene il percorso del file da analizzare mArchiveSourcePath = sourceFile.getPath(); //Se non si deve analizzare un tipo di file, si salta e si restituisce il metodo if (!sourceFile.isFile()) { Log.w(TAG, "Omettendo directory: " + mArchiveSourcePath); //更新错误信息 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } //Se il file non termina con .apk e il flag non è stato determinato come APK, restituisce anche if (!isPackageFilename(sourceFile.getName())) && (flags&PARSE_MUST_BE_APK) != 0) { if ((flags&PARSE_IS_SYSTEM) == 0) { //Ci aspettiamo di avere file non-.apk nella directory di sistema, // therefore don't warn about them. Log.w(TAG, "Skipping non-package file: "+mArchiveSourcePath); } //更新错误信息 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d( TAG, "Scanning package: "+ mArchiveSourcePath); XmlResourceParser parser = null; AssetManager assmgr = null; boolean assetError = true; try { assmgr = new AssetManager(); //将一个文件添加到AssetManager中并返回一个唯一标识 int cookie = assmgr.addAssetPath(mArchiveSourcePath); if(cookie != 0) { //通过标识去AssetManager中找到标识对应资源中的Manifest清单文件,并返回一个XML的解析器 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml"); //走到这里证明一切顺利 assetError = false; XmlUtils.skipCurrentTag(parser); Log.w(TAG, "Failed adding asset path:\+mArchiveSourcePath); } } catch (Exception e) { Log.w(TAG, "Unable to read AndroidManifest.xml of "); + mArchiveSourcePath, e); } if(assetError) { if (assmgr != null) assmgr.close(); mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; return null; } String[] errorText = new String[1]; Package pkg = null; Exception errorException = null; try { //XXXX todo: è necessario determinare la configurazione corretta. Resources res = new Resources(assmgr, metrics, null); //Questo è il metodo che effettivamente analizza il package, è un metodo privato pkg = parsePackage(res, parser, flags, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } if (pkg == null) { if (errorException != null) { Log.w(TAG, mArchiveSourcePath, errorException); XmlUtils.skipCurrentTag(parser); Log.w(TAG, mArchiveSourcePath + " (at " + parser.getPositionDescription() + "): " + errorText[0]); } parser.close(); assmgr.close(); if (mParseError == PackageManager.INSTALL_SUCCEEDED) { Log.w(TAG, "<manifest> has more than one <application>"); } return null; }
parserPackage ha chiamato un altro parserPackage sovraccaricato
private Package parsePackage( Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { AttributeSet attrs = parser; //Ogni volta che si chiama questo metodo, svuota queste variabili mParseInstrumentationArgs = null; mParseActivityArgs = null; mParseServiceArgs = null; mParseProviderArgs = null; //这里调用这个方法获得包名 String pkgName = parsePackageName(parser, attrs, flags, outError); if (pkgName == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } int type; final Package pkg = new Package(pkgName); boolean foundApp = false; //从资源里获得AndroidManifest的数组 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifest) //继续挖掘出版本号 pkg.mVersionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCode, 0); //获取版本名 pkg.mVersionName = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_versionName, 0); if (pkg.mVersionName != null) { pkg.mVersionName = pkg.mVersionName.intern(); } //获得sharedUserId String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { //验证包名是否符合规则 String nameError = validateName(str, true); if (nameError != null && !"android".equals(pkgName)) { outError[0] = "<manifest> specifica un nome badSharedUserId non corretto \"" + str + "\": " + nameError; mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; return null; } pkg.mSharedUserId = str.intern(); pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } sa.recycle(); // Posizione di installazione pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); // Le risorse boolean sono -1, quindi 1 significa che non conosciamo il valore. int supportsSmallScreens = 1; int supportsNormalScreens = 1; int supportsLargeScreens = 1; int resizeable = 1; int anyDensity = 1; int outerDepth = parser.getDepth(); // Il momento cruciale è arrivato, la vera解析 ha iniziato while ((type=parser.next()) != parser.END_DOCUMENT && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { if (type == parser.END_TAG || type == parser.TEXT) { if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { } String tagName = parser.getName(); outError[0] = "<manifest> has more than one <application>"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; else { } Log.w(TAG, "<manifest> has more than one <application>"); return null; XmlUtils.skipCurrentTag(parser); continue; foundApp = true; if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { } } else if (tagName.equals("permission-group")) { } return null; } if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) { else if (tagName.equals("permission")) { return null; } } if (parsePermission(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("permission-tree")) { if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) { return null; } } else if (tagName.equals("uses-permission")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestUsesPermission); // Note: don't allow this value to be a reference to a resource // che potrebbe cambiare. String name = sa.getNonResourceString( com.android.internal.R.styleable.AndroidManifestUsesPermission_name); sa.recycle(); ................................................... ................................................... ...................................................Spazio limitato
Ecco come si analizzano diversi elementi con diversi metodi, l'ordine di chiamata è il seguente:
In realtà ci sono molte piccole tecniche in questi piccoli metodi, se sei interessato, puoi assaporarli attentamente.
Chi è interessato a ulteriori contenuti su Android può consultare le sezioni speciali di questo sito: 'Introduzione e avanzamento alla programmazione Android', 'Trucchi di debug e soluzioni ai problemi comuni di Android', 'Sommarizzazione dell'uso dei componenti di base di Android', 'Sommarizzazione delle tecniche di View Android', 'Sommarizzazione delle tecniche di layout Android' e 'Sommarizzazione dell'uso dei controlli Android'.
Spero che il contenuto di questo articolo possa essere utile per la progettazione di applicazioni Android.
Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, è di proprietà del rispettivo autore, il contenuto è stato contribuito autonomamente dagli utenti di Internet e caricato autonomamente, il sito web non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, invia un'e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, il sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.