يعرض هذا المستند أفضل الممارسات للمساعدة في تشخيص المشكلات وضمان تعمل الملفات الشخصية الأساسية على نحو سليم لتحقيق أكبر فائدة.
مشاكل الإصدار
في حال نسخ مثال "الملفات الشخصية الأساسية" في قسم Now in Android (الآن في Android) نموذج تطبيق، قد تواجه تعذُّر الاختبار أثناء مَهمّة "الملف الشخصي الأساسي". الإشارة إلى عدم إمكانية إجراء الاختبارات على المحاكي:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
تحدث الإخفاقات لأن Now في Android يستخدم جهازًا مُدارًا من Gradle إنشاء الملفات الشخصية الأساسية ومن المتوقع حدوث الإخفاقات، لأنك عادةً ما عدم تشغيل مقاييس الأداء على محاكي ومع ذلك، نظرًا لأنك لا جمع مقاييس الأداء عند إنشاء ملفات شخصية أساسية، يمكنك مجموعة "الملف الشخصي الأساسي" على أدوات المحاكاة لتيسير الوصول إليها. لاستخدام "المقياس الأساسي" باستخدام المحاكي، يمكنك تنفيذ عملية الإنشاء والتثبيت من سطر الأوامر وتعيين وسيطة لتفعيل قواعد الملفات الشخصية الأساسية:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
ويمكنك بدلاً من ذلك إنشاء إعدادات تشغيل مخصّصة في "استوديو Android" من أجل تفعيل الملفات الشخصية غير المرجعية على أدوات المحاكاة من خلال اختيار تشغيل > تعديل الإعدادات:
مشاكل التثبيت
تأكَّد من أنّ ملف APK أو AAB الذي تنشئه هو من إصدار إصدار يتضمن
الملفات الشخصية المرجعية وتتمثل أسهل طريقة للتحقق من ذلك في فتح APK في
"استوديو Android" من خلال النقر على إنشاء > تحليل APK، مما يؤدي إلى فتح
APK، وتبحث عن الملف الشخصي في /assets/dexopt/baseline.prof
الملف:
ويجب تجميع الملفات الشخصية الأساسية على الجهاز الذي يُشغِّل التطبيق. للاثنين
عمليات تثبيت متجر التطبيقات والتطبيقات المثبتة باستخدام
PackageInstaller
، يحدث التجميع على الجهاز فقط كجزء من التطبيق
التثبيت. عند تثبيت التطبيق من مصدر غير معروف من "استوديو Android"
باستخدام أدوات سطر الأوامر، فإن مكتبة Jetpack ProfileInstaller
هي
المسئول عن إدراج الملفات الشخصية في قائمة الانتظار للتجميع خلال
وعملية تحسين DEX للخلفية. في هذه الحالات، إذا أردت التأكد من أنّ
يتم استخدام الملفات الشخصية المرجعية، قد تحتاج إلى:
فرض تجميع الملفات الشخصية الأساسية: يتيح لك ProfileVerifier
الاستعلام عن حالة تثبيت الملف الشخصي وتجميعه، كما هو موضح في
في المثال التالي:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
تقدم رموز النتائج التالية تلميحات عن سبب بعض المشكلات:
RESULT_CODE_COMPILED_WITH_PROFILE
- يتم تثبيت الملف الشخصي وتجميعه واستخدامه عند تشغيل التطبيق. هذا النمط هو النتيجة التي تريد الحصول عليها.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- لم يتم العثور على أي ملف شخصي في ملف APK أو AAB قيد التشغيل. تأكد من استخدام إصدار نسخة تتضمّن الملفات الشخصية الأساسية في حال ظهور هذا الخطأ، تحتوي حزمة APK على ملف شخصي.
RESULT_CODE_NO_PROFILE
- لم يتم تثبيت أي ملف شخصي لهذا التطبيق عند تثبيت التطبيق من خلال التطبيق.
أو مدير الحزمة. السبب الرئيسي لحدوث رمز الخطأ هو أن ملف التعريف
لم يتم تشغيل أداة التثبيت بسبب إيقاف
ProfileInstallerInitializer
. يُرجى ملاحظة أنّه عند الإبلاغ عن هذا الخطأ، كان لا يزال هناك ملف شخصي مضمّن في التطبيق. عند عدم العثور على ملف شخصي مضمّن، يتم عرض رمز الخطأRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- تم العثور على ملف شخصي في APK أو AAB، وتمت إضافته إلى قائمة الانتظار للتجميع. عندما
تم تثبيت ملف التعريف بواسطة
ProfileInstaller
، وهو في قائمة انتظار التجميع في المرة التالية التي يشغِّل فيها النظام تحسين DEX في الخلفية. الملف الشخصي ليس نشطة إلى أن تكتمل عملية التجميع. لا تحاول قياس القيمة المرجعية الملفات الشخصية إلى أن تكتمل عملية التجميع. قد تحتاج إلى فرض تجميع الملفات الشخصية الأساسية: لن يحدث هذا الخطأ عندما يتم تثبيت التطبيق من متجر التطبيقات أو مدير الحزم على الأجهزة التي تعمل الإصدار 9 من نظام التشغيل Android (API 28) والإصدارات الأحدث، لأنّ التجميع أثناء التثبيت. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- يتم تثبيت ملف شخصي غير متطابق ويتم تجميع التطبيق باستخدامه.
تكون هذه نتيجة التثبيت من خلال متجر Google Play أو مدير الحزم.
يُرجى العِلم أنّ هذه النتيجة تختلف عن
RESULT_CODE_COMPILED_WITH_PROFILE
للأسباب التالية: فإن الملف الشخصي غير المطابق سيجمع فقط أي طرق لا تزال مشتركة بين الملف الشخصي والتطبيق. الملف الشخصي أصغر فعليًا من ومتوقعًا، وسيتم تجميع عدد أقل من الطرق التي تم تضمينها في المجموعة المرجعية ملفك التجاري. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
- لم يتمكن
ProfileVerifier
من كتابة ملف ذاكرة التخزين المؤقت لنتائج التحقق. يمكن أن قد يحدث بسبب حدوث خطأ في أذونات مجلد التطبيق أو إذا عدم توفّر مساحة كافية على القرص على الجهاز RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
يتوافق تطبيق - ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
مع نظام التشغيل Android 9 (المستوى 28 من واجهة برمجة التطبيقات) والإصدارات الأحدث فقط. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
- يتم تشغيل
PackageManager.NameNotFoundException
عند الاستعلام عنPackageManager
لحزمة التطبيق من المفترض أن يحدث هذا نادرًا. تجربة إلغاء تثبيت التطبيق وإعادة تثبيت كل التطبيقات RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- هناك ملف ذاكرة تخزين مؤقت لنتائج إثبات الملكية، ولكن لا يمكن قراءته. هذا النمط نادرًا ما يحدث. حاول إلغاء تثبيت التطبيق وإعادة تثبيت كل شيء.
استخدام ProfileVerifier في مرحلة الإنتاج
في الإصدار العلني، يمكنك استخدام ProfileVerifier
مع
مكتبات إعداد تقارير الإحصاءات، مثل إحصاءات Google لبرنامج Firebase
إنشاء أحداث إحصاءات تشير إلى حالة الملف الشخصي. على سبيل المثال،
ينبهك سريعًا إذا تم طرح إصدار جديد من التطبيق لا يحتوي على
الملفات الشخصية المرجعية
تجميع الملفات الشخصية الأساسية
إذا كانت حالة تجميع الملفات الشخصية الأساسية
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
، يمكنك فرض الميزة فورًا.
التجميع باستخدام adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
التحقّق من حالة التجميع بدون ProfileVerifier
إذا كنت لا تستخدم ProfileVerifier
، يمكنك التحقّق من حالة التجميع باستخدام
adb
، مع أنّه لا يقدّم إحصاءات مفصّلة مثل ProfileVerifier
:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
يؤدي استخدام adb
إلى إنتاج نتيجة مشابهة لما يلي:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
تشير قيمة الحالة إلى حالة تجميع الملف الشخصي وهي إحدى القيم التالية:
حالة التحويل البرمجي | المعنى |
---|---|
speed‑profile |
يوجد ملف تعريف تم تجميعه ويتم استخدامه. |
verify |
لا يوجد ملف تعريف مجمعة. |
لا تعني الحالة verify
أنّ حزمة APK أو AAB لا تحتوي على ملف شخصي.
لأنه يمكن وضعه في قائمة الانتظار للتجميع عن طريق تحسين DEX التالي في الخلفية
المهمة.
تشير قيمة السبب إلى ما يؤدي إلى تجميع الملف الشخصي يتم عرض إحدى القيم التالية:
السبب | المعنى |
---|---|
install‑dm
|
جمعت Google ملفًا شخصيًا مرجعيًا يدويًا أو من إعداد Google. يمكنك تشغيل المحتوى عندما يكون التطبيق مثبّتًا. |
bg‑dexopt
|
تم تجميع ملف شخصي عندما كان جهازك غير نشِط لفترة قصيرة. قد يكون هذا ملف تعريف شخصي أو قد يكون ملفًّا التي يتم جمعها أثناء استخدام التطبيق. |
cmdline
|
تم تشغيل التحويل باستخدام adb. قد يكون هذا ملف تعريف شخصي أو قد يكون ملفًّا التي يتم جمعها أثناء استخدام التطبيق. |
مشاكل في الأداء
يعرض هذا القسم بعضًا من أفضل الممارسات للتحديد وقياس الأداء بشكل صحيح الملفات الشخصية الأساسية للاستفادة منها إلى أقصى حد.
قياس أداء مقاييس بدء التشغيل بشكل صحيح
ستكون الملفات الشخصية الأساسية أكثر فعالية إذا كانت مقاييس الشركات الناشئة: محددة جيدًا. إنّ المقياسَين الرئيسيَّين هما الوقت المُستغرَق للعرض الأولي (TTID). الوقت المُستغرَق للعرض الكامل (TTFD):
يحدث TTID عندما يرسم التطبيق أول إطار له. من المهم أن تجعل هذا قصيرًا قدر الإمكان، لأنّ عرض عنصر ما يوضّح للمستخدم أنّ التطبيق قيد التشغيل. يمكنك أيضًا عرض مؤشر تقدم غير محدد لإظهار أن التطبيق سريع الاستجابة.
يشير مصطلح TTFD إلى الوقت الذي يمكن فيه التفاعل مع التطبيق. من المهم أن تضع هذا قصير قدر الإمكان لتجنب استياء المستخدم. إذا قمت بالإشارة بشكل صحيح هذا يعني أنك تخبر النظام بأن الرمز الذي يتم تشغيله في طريقه إلى TTFD في مرحلة بدء تشغيل التطبيق. يزيد احتمال أن يضع النظام هذا الرمز في الملف الشخصي. نتيجة لذلك.
ويجب إبقاء كل من TTID وTTFD منخفضَين قدر الإمكان لكي يبدو تطبيقك مستجيبًا.
يمكن للنظام اكتشاف TTID وعرضه في Logcat والإبلاغ عنه كجزء من البرنامج.
ومقاييس أداء الشركات الناشئة ومع ذلك، يتعذر على النظام تحديد TTFD،
مسئولية التطبيق عن الإبلاغ عند وصوله إلى واجهة تفاعلية مرسومة بالكامل
الولاية. يمكنك إجراء ذلك من خلال الاتصال بالرقم reportFullyDrawn()
ReportDrawn
إذا كنت تستخدم Jetpack Compose. إذا كان لديك عدة
المهام التي في الخلفية يجب إكمالها جميعًا قبل احتساب التطبيق بشكل كامل
مرسومة، يمكنك استخدام FullyDrawnReporter
، كما هو موضح في تحسين
ودقة توقيت بدء التشغيل.
الملفات الشخصية للمكتبة والملفات الشخصية المخصّصة
وعند قياس تأثير الملفات الشخصية، قد يكون من الصعب فصل مزايا الملفات الشخصية للتطبيق من الملفات الشخصية التي تساهم بها المكتبات، مثل مكتبات Jetpack. عند إنشاء حزمة APK، يضيف المكوّن الإضافي لنظام Gradle المتوافق مع Android أي في ملحقات المكتبة وكذلك في ملفك الشخصي المخصص. هذا جيد لتحسين الأداء العام، ويُنصح به مع إصدارات الإصدارات. ومع ذلك، فإنه يجعل من الصعب قياس مقدار مكاسب الأداء الإضافية التي تأتي من ملفك الشخصي المخصص.
طريقة سريعة للاطلاع يدويًا على التحسين الإضافي الذي يقدمه حسابك هو إزالته، وإدارة مقاييس الأداء. ثم استبدله وشغِّل للمقاييس مرة أخرى. وستعرض لك المقارنة بين الاثنين التحسينات التي أجراها والملفات الشخصية للمكتبة فقط والملفات الشخصية للمكتبة بالإضافة إلى ملفك الشخصي المخصص.
تتوفّر طريقة تلقائية لمقارنة الملفات الشخصية من خلال إنشاء نسخة جديدة من الإصدار
على الملفات الشخصية للمكتبة فقط وليس على ملفك الشخصي المخصّص. مقارنة
من هذه الصيغة إلى صيغة الإصدار التي تتضمن
الملفات الشخصية للمكتبة وملفاتك الشخصية المخصصة. يوضح المثال التالي كيف
لإعداد خيار يتضمّن الملفات الشخصية للمكتبة فقط إضافة صيغة جديدة
باسم releaseWithoutCustomProfile
في وحدة المستهلك في ملفك الشخصي، وهي
عادةً وحدة تطبيقك:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
يزيل مثال الرمز السابق تبعية baselineProfile
من جميع
خيارات المنتجات وتطبيقها بشكل انتقائي على خيار المنتج release
فقط. قد يبدو
من البديهي أن ملفات المكتبة الشخصية لا تزال تتم إضافتها عندما
تتم إزالة الاعتمادية على وحدة منتِج الملف الشخصي. ومع ذلك، فإن هذه الوحدة
مسؤولة فقط عن إنشاء ملف تعريف مخصص. نظام Gradle المتوافق مع Android
لا يزال المكوّن الإضافي قيد التشغيل لجميع المتغيرات، وهو مسؤول عن تضمين
ملفات المكتبة الشخصية.
عليك أيضًا إضافة الصيغة الجديدة إلى وحدة إنشاء الملفات الشخصية. في هذه الدورة،
على سبيل المثال، تُسمى وحدة المنتِج :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Groovy
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
عند تشغيل مقياس الأداء من "استوديو Android"، اختَر
صيغة واحدة (releaseWithoutCustomProfile
) لقياس الأداء من خلال المكتبة فقط
أو اختيار صيغة release
لقياس الأداء من خلال المكتبة
والملفات الشخصية المخصصة.
تجنُّب بدء تشغيل التطبيق المرتبط بوحدات الإدخال والإخراج
إذا كان تطبيقك يُجري العديد من مكالمات وحدات الإدخال والإخراج (I/O) أو اتصالات الشبكات أثناء بدء التشغيل، عليك اتّباع الخطوات التالية: يمكن أن يؤثر ذلك سلبًا على وقت بدء تشغيل التطبيق ودقة بدء التشغيل لقياس الأداء. يمكن أن تستغرق هذه المكالمات الكبيرة فترات زمنية غير محدّدة والتي يمكن أن تختلف بمرور الوقت وحتى بين التكرارات للمقياس نفسه. مؤتمر I/O تكون الاتصالات أفضل بشكل عام من اتصالات الشبكة، حيث يمكن يتأثر بعوامل خارجية عن الجهاز وعلى الجهاز نفسه. تجنب الاتصال بالشبكة أثناء بدء التشغيل. استخدِم وحدات الإدخال والإخراج في الحالات التي لا مفرّ منها.
ننصحك بجعل بنية تطبيقك تتوافق مع بدء تشغيل التطبيق بدون الاتصال بشبكة طلبات وحدات الإدخال والإخراج، حتى لو تم استخدامها فقط عند قياس أداء بدء التشغيل يساعد هذا في ضمان أقل تباين ممكن بين التكرارات المختلفة لمقاييس الأداء.
إذا كان تطبيقك يستخدم Hilt، يمكنك تقديم ملفات وهمية مرتبطة بوحدات الإدخال والإخراج. عمليات التنفيذ عند قياس الأداء في Micromic and Hilt.
تغطية جميع رحلات المستخدم المهمة
من المهم أن تغطي بدقة جميع رحلات المستخدم المهمة في إنشاء الملفات الشخصية الأساسية لن يتم تناول أي رحلات مستخدم لم يتم تناولها تم تحسينها بواسطة الملفات الشخصية من الأشخاص الذين لم يروا الإعلانات تشمل الملفات الشخصية المرجعية الأكثر فاعلية جميع رحلات المستخدم الشائعة من الشركات الناشئة، بالإضافة إلى تجربة المستخدم داخل التطبيق الحساس للأداء رحلات مثل قوائم التمرير.