請參閱以下內容,瞭解為何在 Android Automotive 實作中,執行階段資源覆蓋 (RRO) 可能無法正常運作。
相關說明文件
如要進一步瞭解 Android 中的 RRO,請參閱「在執行階段變更應用程式資源的值」。請務必持續警戒 logcat
輸出內容,掌握整個流程的運作情況。
步驟 1:列出 RRO
如要列出 RRO,請按照下列步驟操作:
執行下列指令:
adb shell cmd overlay list --user current
畫面會顯示以下輸出內容:
com.android.systemui [ ] com.android.theme.icon_pack.rounded.systemui [ ] com.android.theme.icon_pack.filled.systemui [ ] com.android.theme.icon_pack.circular.systemui com.android.permissioncontroller --- com.android.permissioncontroller.googlecarui.rro
確認清單中是否顯示您的 RRO。以下指標表示 RRO 狀態:
指標 RRO 狀態 [ ]
已安裝,可啟用。 [X]
已安裝並啟用。 ---
已安裝,但含有錯誤。 如果 RRO 未列在要重疊的目標套件名稱下方,表示系統不會安裝 RRO。
步驟 2:啟用及停用 RRO
如果已安裝 RRO:
使用下列指令啟用 (或停用) RRO:
adb shell cmd overlay [enable/disable] --user current [your RRO package name]
步驟 3:確認已安裝 RRO
如要確認裝置上已安裝 RRO,或排解為何未啟用 RRO,請按照下列步驟操作:
執行下列指令:
adb shell cmd overlay dump [your RRO package name]
畫面會顯示類似以下的輸出內容:
com.android.car.rotaryplayground.googlecarui.rro:0 { mPackageName...........: com.android.car.rotaryplayground.googlecarui.rro mUserId................: 0 mTargetPackageName.....: com.android.car.rotaryplayground mTargetOverlayableName.: car-ui-lib mBaseCodePath..........: /product/overlay/googlecarui-com-android-car-rotaryplayground/googlecarui-com-android-car-rotaryplayground.apk mState.................: STATE_MISSING_TARGET mIsEnabled.............: true mIsMutable.............: true mPriority..............: 10 mCategory..............: BypassIdMapV1 } com.android.car.rotaryplayground.googlecarui.rro:10 { mPackageName...........: com.android.car.rotaryplayground.googlecarui.rro mUserId................: 10 mTargetPackageName.....: com.android.car.rotaryplayground mTargetOverlayableName.: car-ui-lib mBaseCodePath..........: /product/overlay/googlecarui-com-android-car-rotaryplayground/googlecarui-com-android-car-rotaryplayground.apk mState.................: STATE_MISSING_TARGET mIsEnabled.............: true mIsMutable.............: true mPriority..............: 10 mCategory..............: BypassIdMapV1 }
找出安裝 RRO 的使用者。在上例中,RRO 可供使用者
0
和 user10
使用 (請參閱頂端程式碼區塊中的mUserId
值)。如要為使用者啟用 (或停用) RRO,請參閱步驟 2。
如何查看
mState
的值:STATE_ENABLED
和STATE_ENABLED_IMMUTABLE
系統會啟用 RRO 並套用至目標。STATE_MISSING_TARGET
:目標未安裝。STATE_NO_IDMAP
:AndroidManifest.xml
、overlays.xml
或overlayable.xml
檔案的設定方式有誤。使用adb logcat
執行記錄檔,並搜尋關鍵字idmap
來找出錯誤。請參閱步驟 4 和 5。STATE_UNKNOWN
。OverlayManagerService
發生問題。
步驟 4:檢查 AndroidManifest.xml
如要驗證 AndroidManifest.xml
:
請查看
targetName
和targetPackage
。android:targetName
應與目標應用程式中定義的疊加群組具有相同的值。只有指定疊加層時,才需要提供這個值。android:targetPackage
一律為必要項目,且應包含目標應用程式的套件名稱。檢查 RRO 是否為靜態狀態。根據預設,系統會在啟動期間啟用靜態 RRO。根據預設,系統不會在開機時啟用動態 RRO。如需啟用動態 RRO 的其他方法,請參閱「在執行階段變更應用程式資源的值」。
檢查靜態 RRO 的優先順序 (動態 RRO 優先順序一律設為
Integer.MAX_VALUE
,且套用順序取決於啟用時間)。同一個目標可以套用多個 RRO。優先順序較高的 RRO 會最後套用。以 0 到 10 的評分制,10 分為最高,0 分為最低。
步驟 5:檢查 overlays.xml
檢查
overlays.xml
,確認您要重疊的所有資源都已在這個檔案中定義。例如,請看以下overlays.xml
:<overlay> <item target="string/app_name" value="@string/overlaid_app_name" /> </overlay>
您必須確保:
- 目標應用程式中已有
string
項名為「app_name
」的資源。 - RRO 中已存在名稱為
overlaid_app_name
的string
資源。
- 目標應用程式中已有
如果目標有
overlayable.xml
檔案,請確認該檔案包含app_name
。請務必在AndroidManifest.xml
檔案中使用正確的targetName
(步驟 4)。例如:
<overlay> <item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar" /> <item target="id/car_ui_toolbar_background" value="@id/car_ui_toolbar_background" /> <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf" /> </overlay>
步驟 6:轉儲 idmap
此時,應已解決 RRO 的所有問題。接著,請轉儲 RRO 的 idmap
,瞭解資源的解析方式,以及為何解析為與預期不同的值。
如何在裝置上找到
idmap
的路徑:adb shell su ls data/resource-cache
如要轉儲該檔案的內容,請按照下列步驟操作:
adb root adb shell idmap2 dump --idmap-path [path to your RRO idmap file]
例子:
adb shell idmap2 dump --idmap-path data/resource-cache/system@app@CarUiPortraitLauncherReferenceRRO@CarUiPortraitLauncherReferenceRRO.apk@idmap
輸出內容會與以下內容類似:輸出結果會顯示 RRO 中的哪個 ID 會對應至目標中的哪個 ID,以及疊加資源的名稱。
target apk path : /system/priv-app/CarMediaApp/CarMediaApp.apk overlay apk path : /product/overlay/googlecarui-com-android-car-media/googlecarui-com-android-car-media.apk 0x7f040008 -> 0x7f010000 bool/car_ui_toolbar_logo_fills_nav_icon_space 0x7f040009 -> 0x7f010001 bool/car_ui_toolbar_nav_icon_reserve_space 0x7f04000b -> 0x7f010002 bool/car_ui_toolbar_tab_flexible_layout 0x7f04000c -> 0x7f010003 bool/car_ui_toolbar_tabs_on_second_row 0x7f09006c -> 0x7f020000 id/car_ui_base_layout_content_container 0x7f090073 -> 0x7f020001 id/car_ui_recycler_view 0x7f090074 -> 0x7f020002 id/car_ui_scroll_bar 0x7f090075 -> 0x7f020003 id/car_ui_scrollbar_page_down 0x7f090076 -> 0x7f020004 id/car_ui_scrollbar_page_up 0x7f090077 -> 0x7f020005 id/car_ui_scrollbar_thumb 0x7f090078 -> 0x7f020006 id/car_ui_scrollbar_track 0x7f09007a -> 0x7f020007 id/car_ui_toolbar_background 0x7f09007e -> 0x7f020008 id/car_ui_toolbar_logo 0x7f090084 -> 0x7f020009 id/car_ui_toolbar_menu_items_container 0x7f090085 -> 0x7f02000a id/car_ui_toolbar_nav_icon 0x7f090086 -> 0x7f02000b id/car_ui_toolbar_nav_icon_container 0x7f090087 -> 0x7f02000c id/car_ui_toolbar_progress_bar 0x7f090089 -> 0x7f02000d id/car_ui_toolbar_row_separator_guideline 0x7f09008d -> 0x7f02000e id/car_ui_toolbar_search_view_container 0x7f09008f -> 0x7f02000f id/car_ui_toolbar_subtitle 0x7f090092 -> 0x7f020010 id/car_ui_toolbar_tabs 0x7f090093 -> 0x7f020011 id/car_ui_toolbar_title 0x7f090094 -> 0x7f020012 id/car_ui_toolbar_title_container 0x7f090095 -> 0x7f020013 id/car_ui_toolbar_title_logo 0x7f090096 -> 0x7f020014 id/car_ui_toolbar_title_logo_container 0x7f0c0024 -> 0x7f030000 layout/car_ui_base_layout_toolbar 0x7f0c0035 -> 0x7f030001 layout/car_ui_recycler_view 0x7f0c0038 -> 0x7f030002 layout/car_ui_toolbar 0x7f0c003f -> 0x7f030003 layout/car_ui_toolbar_two_row
使用下列指令查詢特定資源,瞭解它們的對應方式:
adb shell cmd overlay lookup --verbose --user 10 com.android.car.ui.paintbooth com.android.car.ui.paintbooth:color/widget_background
輸出內容是資源的最終值:
#ff7986cb
您也可以從 APK 中轉儲版面配置檔案,查看與上述輸出內容相符的已解析 ID:
aapt2 dump xmltree $OUT/system/priv-app/sharedlibraryclient/sharedlibraryclient.apk --file res/layout/activity_main.xml
輸出結果如下:
N: android=http://schemas.android.com/apk/res/android (line=2)
N: app=http://schemas.android.com/apk/res-auto (line=2)
N: lib=http://schemas.android.com/apk/com.android.car.ui.sharedlibrary.test (line=2)
E: androidx.constraintlayout.widget.ConstraintLayout (line=2)
A: http://schemas.android.com/apk/res/android:layout_width(0x010100f4)=-1
A: http://schemas.android.com/apk/res/android:layout_height(0x010100f5)=-1
E: TextView (line=19)
A: http://schemas.android.com/apk/res/android:layout_width(0x010100f4)=-2
A: http://schemas.android.com/apk/res/android:layout_height(0x010100f5)=-2
A: http://schemas.android.com/apk/res/android:text(0x0101014f)=@0x020f0000
A: http://schemas.android.com/apk/res-auto:layout_constraintBottom_toBottomOf(0x7f0200fb)=0
A: http://schemas.android.com/apk/res-auto:layout_constraintLeft_toLeftOf(0x7f02010e)=0
A: http://schemas.android.com/apk/res-auto:layout_constraintRight_toRightOf(0x7f020112)=0
A: http://schemas.android.com/apk/res-auto:layout_constraintTop_toTopOf(0x7f020118)=0
E: com.android.car.ui.sharedlibrary.test.MyRecyclerView (line=28)
A: http://schemas.android.com/apk/res/android:layout_width(0x010100f4)=-2
A: http://schemas.android.com/apk/res/android:layout_height(0x010100f5)=-2
A: http://schemas.android.com/apk/com.android.car.ui.sharedlibrary.test:implClass="HelloWorld!" (Raw: "HelloWorld!")
E: com.android.car.ui.sharedlibraryclient.CustomView (line=34)
A: http://schemas.android.com/apk/res/android:layout_width(0x010100f4)=-2
A: http://schemas.android.com/apk/res/android:layout_height(0x010100f5)=-2
A: http://schemas.android.com/apk/res-auto:implClass2(0x7f0200e8)="HelloWorld!!" (Raw: "HelloWorld!!")