Android 10 Q API级别29上boot_completed无法正常工作

20
我有一个应用程序,在引导后启动Intent,适用于 Android 6 到 Android 9 API 级别28。
但是这个代码在 Android 10 API 级别29上不起作用,广播根本没有接收到任何事件,并且在引导后没有运行 MyClassBroadcastReceiver 的 onReceive 方法。在 Android 10 上需要额外的权限或配置吗?
示例中的 Manifest 部分:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.softniels.autostartonboot">

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service
        android:name="com.softniels.autostartonboot.ForegroundService"
        android:label="My Service">
        <intent-filter>
            <action android:name="com.softniels.autostartonboot.ForegroundService" />
        </intent-filter>
    </service>

    <receiver
        android:name=".StartMyServiceAtBootReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        </intent-filter>
    </receiver>

</application>

这里是在Android 10上无法运行的部分。

public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            Log.i("onReceive", "call onReceive ACTION_BOOT_COMPLETED");
            Intent i = new Intent(context, MainActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
        }
    }
}

1
我也注意到了这一点。它在Android 9及以下版本中运行正常,但在10上却不行。你找到解决方法了吗? - user1195883
1
同样的问题在这里。尝试了一些东西,新的标志,但是什么都不起作用。我可以在接收器上启动一个ToastLog.i(),但似乎context.startActivity()没有启动。 - Carlos.V
@Carlos.V 你解决了这个问题吗? - makis.k
@makis.k 你想要实现什么目标? - Carlos.V
4个回答

21

我知道这可能有些陈旧,但是我面临了同样的问题,并根据以下方法解决:

https://developer.android.com/guide/components/activities/background-starts

我想到的最简单的解决方法就是简单地添加

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

同时设置接收器:

<receiver
android:name=".BootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

到清单文件中。

接收方代码:

@Override
public void onReceive(Context context, Intent intent) {
    if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
//            Intent n =  context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
 //            n.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 
 //    Intent.FLAG_ACTIVITY_CLEAR_TASK);
 //            context.startActivity(n);

        Intent myIntent = new Intent(context, MainActivity.class);
        myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(myIntent);
    }
}

两个选项都可以。我唯一看到的缺点是,应用程序加载需要相当长的时间(根据我的测试可能需要长达10秒)。

如果其他人也遇到此问题,则将其保留在此处。

这仅适用于安卓10及以上版本。需要请求“允许在其他应用上显示”的权限。

这需要绘制覆盖层,可使用以下方法完成:

if (!Settings.canDrawOverlays(getApplicationContext())) {
            Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            Uri uri = Uri.fromParts("package", getPackageName(), null);

            myIntent.setData(uri);
            startActivityForResult(myIntent, REQUEST_OVERLAY_PERMISSIONS);
            return;
        }

2
这对我也起作用了,但只有在将if (!Settings.canDrawOverlays(getApplicationContext())) { startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)); }添加到MainActivity.onCreate()后,手动启动应用程序并授予权限才行。(请参见android.permission.SYSTEM_ALERT_WINDOW。) - legolas108
@legolas108 是的,我忘记添加需要权限的要求了。我会加上的。 - Dan Baruch
1
@prototype86 是的,这个适用于Android 10。 - Dan Baruch
你好,@Dan Baruch,我尝试了相同的方法并实现了相同的步骤,但它仍然无法工作,设备启动时它不会自动启动。 - Navin
1
让我们在聊天中继续这个讨论 - Dan Baruch
显示剩余12条评论

1

我在清单中使用了这个权限解决了它:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> 

在主活动中:

    if (!Settings.canDrawOverlays(getApplicationContext())) {
        startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
    }

Settings的正确导入方式是:android.provider

应用第一次启动时,将提示权限以控制哪些应用程序可以在其他应用程序上方绘制。下次设备启动时,应用程序将使用典型的广播接收器启动。

这里是文档。

enter image description here


1
我找到了一个“解决方案”适合我。
    public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                Log.e(TAG, "launching from special > API 28 (" + Build.VERSION.SDK_INT + ")"); // You have to schedule a Service
                JobServiceScheduler jobServiceScheduler = new JobServiceScheduler(context);
                boolean result = jobServiceScheduler.scheduleMainService(20L); // Time you will wait to launch
            } else {
                Log.e(TAG, "launching from normal < API 29"); // You can still launch an Activity 
                try {
                    Intent intentMain = new Intent(context, YourActivity.class);
                    intentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    if (Build.VERSION.SDK_INT < 28) {
                        context.startService(intentMain);
                    } else {
                        context.startForegroundService(intentMain);
                    }
                } catch (ActivityNotFoundException ex) {
                    Log.e(TAG, "ActivityNotFoundException" + ex.getLocalizedMessage());
                }
            }
    }

    boolean scheduleMainService(Long segundos) {
        ComponentName serviceComponent = new ComponentName(context, YourService.class);
        JobInfo.Builder builder = getCommonBuilder(serviceComponent, YOUR_SERVICE_JOB_ID);
        builder.setMinimumLatency(TimeUnit.SECONDS.toMillis(segundos / 2)); // wait at least
        builder.setOverrideDeadline(TimeUnit.SECONDS.toMillis(segundos)); // maximum delay
        PersistableBundle extras = new PersistableBundle();
        extras.putLong("time", segundos);
        builder.setExtras(extras);

        JobScheduler jobScheduler = getJobScheduler(context);
        if (jobScheduler != null) {
            jobScheduler.schedule(builder.build());
            return true;
        } else {
            return false;
        }
    }

你好, "getCommonBuilder()" 和 "getJobScheduler()" 在哪里? - dcarl661
@dcarl661 抱歉回复晚了,我已经无法访问这个项目了 :( - Carlos.V
没关系,这给了我一个找寻的思路。 - dcarl661

1

context.startActivity()不能启动,我是通过以下方式解决的:

  private void restartApp( Context mContext) {
    try {
        long restartTime = 1000*5;
        Intent intents = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
        PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intents, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
        }
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接