You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo集成Android Widget添加至桌面崩溃:PendingIntent异常排查

Android Widget 集成 Expo React Native 后配置界面崩溃(PendingIntent$CanceledException)

这个错误的核心是:Widget配置页试图通过PendingIntent把结果返回给AppWidgetManager时,这个PendingIntent已经被系统取消了,大概率和Widget ID传递错误、Intent配置不当,或是Expo集成时的Manifest覆盖有关。下面是具体排查和修复步骤:

1. 盯死Widget ID的传递逻辑

配置Activity启动时,必须从Intent里正确拿到Widget ID,别搞丢了:

// 正确获取Widget ID的代码,直接抄
val appWidgetId = intent?.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
    setResult(RESULT_CANCELED)
    finish()
    return
}

全程用局部变量传递这个ID,别存全局——系统回收内存时容易丢失。

2. 修复返回结果的PendingIntent

这是崩溃的重灾区,确保PendingIntent的创建逻辑没问题:

// 配置完成后返回结果的正确写法
val resultIntent = Intent().apply {
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
}
val pendingIntent = PendingIntent.getActivity(
    this,
    appWidgetId, // 必须用Widget ID当requestCode,保证每个Widget实例的PendingIntent唯一
    resultIntent,
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // Android 12+必须加FLAG_IMMUTABLE
)
setResult(RESULT_OK, resultIntent)
finish()

重点:requestCode一定要用Widget ID,不然多个Widget会互相干扰;Android 12及以上必须加FLAG_IMMUTABLE(如果需要后续修改Intent就用FLAG_MUTABLE)。

3. 检查Expo集成后的Manifest配置

Expo的app.json或者自动生成的AndroidManifest.xml很可能改了你的Activity配置,必须确保:

  • 配置Activity的launchMode是standard或singleTop,绝对不能是singleInstance/singleTask:
    <activity
        android:name=".WidgetConfigActivity"
        android:launchMode="standard"
        android:exported="true"> <!-- 必须开exported,系统才能启动这个Activity -->
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
        </intent-filter>
    </activity>
    
  • AppWidgetProvider的配置里要正确关联配置Activity,widget_info.xml里必须加:
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:configure="com.yourpackage.WidgetConfigActivity"
        <!-- 其他Widget属性 -->
        />
    

4. API请求别抢在结果返回前执行

如果配置页有API请求,一定要等请求完成再返回结果,别提前调用finish():

// 错误示范:先finish再请求,直接导致PendingIntent失效
setResult(RESULT_OK, resultIntent)
finish()
apiService.fetchData().enqueue(...)

// 正确示范:请求完成后再处理结果
apiService.fetchData().enqueue(object : Callback<Data> {
    override fun onResponse(call: Call<Data>, response: Response<Data>) {
        // 先把配置参数存起来
        saveWidgetConfig(appWidgetId, response.body())
        // 再返回结果并关闭页面
        setResult(RESULT_OK, resultIntent)
        finish()
    }

    override fun onFailure(call: Call<Data>, t: Throwable) {
        // 请求失败也要返回取消结果,别挂着
        setResult(RESULT_CANCELED)
        finish()
    }
})

5. 生产构建的混淆检查

Expo生产构建会开混淆,别把Widget相关类搞没了,在proguard-rules.pro里加:

-keep class com.yourpackage.WidgetConfigActivity
-keep class com.yourpackage.MyWidgetProvider
-keepclassmembers class com.yourpackage.WidgetConfigActivity {
    void onCreate(android.os.Bundle);
}

内容的提问来源于stack exchange,提问作者Sergiu Tonț

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:52:32