Glance Widget按需动态交付后无法加载崩溃问题咨询
问题描述
- 应用初始体积2.8MB,集成Glance Widget后飙升至5.3MB,计划采用Dynamic Feature/Delivery实现Widget按需下载,降低初始安装包体积。
- 遇到异常:Widget模块下载完成后仍无法渲染,启动器显示“Can't load widget”。
- 对比现象:
- 设置为安装时交付无错误:
<dist:install-time> <dist:removable dist:value="false"/> </dist:install-time> - 切换为按需交付后问题触发:
<dist:on-demand />
- 设置为安装时交付无错误:
- 错误日志:
Error inflating AppWidget AppWidgetProviderInfo(UserHandle{0}/ComponentInfo{com.example.foo/com.example.foo.glance.ui.glance.MyWidgetReceiver}) android.content.res.Resources$NotFoundException: Resource ID #0x0 at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:240) at android.content.res.Resources.loadXmlResourceParser(Resources.java:2529) at android.content.res.Resources.getLayout(Resources.java:1335) at android.view.LayoutInflater.inflate(LayoutInflater.java:536) at android.appwidget.AppWidgetHostView.getDefaultView(AppWidgetHostView.java:926) at android.appwidget.AppWidgetHostView.applyRemoteViews(AppWidgetHostView.java:579) at android.appwidget.AppWidgetHostView.updateAppWidget(AppWidgetHostView.java:533) at com.android.launcher3.widget.LauncherAppWidgetHostView.updateAppWidget(LauncherAppWidgetHostView.java:247) at android.appwidget.AppWidgetHost.updateAppWidgetView(AppWidgetHost.java:529) at android.appwidget.AppWidgetHost$UpdateHandler.handleMessage(AppWidgetHost.java:158) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8751) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
解决方案
1. 彻底隔离Widget组件与资源
把Widget的AppWidgetProvider实现类、Glance逻辑代码、布局资源、Drawable资源全量迁移到动态feature模块,主模块不能残留任何与Widget关联的资源或代码引用,避免系统加载时混淆资源路径。
2. 修复动态模块资源访问逻辑
崩溃核心是系统启动器无法找到Widget对应的资源,需做以下调整:
- 动态模块的
appwidget-provider配置xml中,所有资源引用(如android:initialLayout)必须使用模块内的相对路径,确保资源完全由动态模块自身管理。 - 禁止在主模块中引用动态模块的资源,所有Widget相关资源的访问都限定在动态模块内部。
3. 模块安装完成后主动刷新Widget列表
用户触发Widget下载后,必须等待动态模块完全安装初始化,再通知系统刷新Widget列表,否则系统无法识别新安装的Widget组件:
val splitInstallManager = SplitInstallManagerFactory.create(context) splitInstallManager.registerListener { sessionState -> if (sessionState.status() == SplitInstallSessionStatus.INSTALLED) { // 发送广播通知系统更新应用组件信息,包括Widget val intent = Intent(Intent.ACTION_PACKAGE_CHANGED).apply { setPackage(context.packageName) addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) } context.sendBroadcast(intent) } }
4. 规范动态模块Manifest配置
确保动态模块的Manifest正确声明交付方式与Widget组件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" package="com.example.foo.widget"> <dist:module dist:instant="false" dist:title="@string/widget_module_title"> <dist:on-demand /> </dist:module> <!-- 完整声明Widget Receiver --> <receiver android:name=".MyWidgetReceiver"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_widget_info" /> </receiver> </manifest>
5. 正确测试动态交付流程
- 不要直接用Android Studio的「Run」按钮测试,必须生成App Bundle,通过Internal App Sharing、Google Play Console或
bundletool生成APK集安装测试,本地直接运行无法模拟真实的动态交付环境。 - 确保测试设备为Android 5.0+,且Google Play服务版本符合动态交付要求。
内容的提问来源于stack exchange,提问作者DTechnlogy
相关产品推荐
相关产品推荐

