`boot_completed` 在 Android 10(API 级别 29)上无法正常工作。

huangapple go评论82阅读模式
英文:

boot_completed not working on Android 10 Q API level 29

问题

我有一个应用程序,在启动后会启动一个意图(Intent),它在Android 6到Android 9 API级别28上工作。

但是这段代码在Android 10 API级别29上不起作用,广播根本没有接收到任何事件,并且在启动后不会在MyClassBroadcastReceiver上运行onReceive方法。是否在Android 10上需要额外的权限或配置?

示例中的关键部分如下:清单文件(Manifest):

<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>
</manifest>

这里是在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);
        }
    }
}
英文:

I have an application that starts an Intent after the boot that works from Android 6 to Android 9 API level 28.

But this code does not work on Android 10 API level 29, Broadcast simply does not receive any events and does not run onReceive on MyClassBroadcastReceiver after the boot. Is there any extra permission on Android 10 or configuration that needs to be done?

Dry part of the example: Manifest:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
package=&quot;com.softniels.autostartonboot&quot;&gt;

&lt;uses-permission android:name=&quot;android.permission.RECEIVE_BOOT_COMPLETED&quot; /&gt;

&lt;application
    android:allowBackup=&quot;true&quot;
    android:icon=&quot;@mipmap/ic_launcher&quot;
    android:label=&quot;@string/app_name&quot;
    android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
    android:supportsRtl=&quot;true&quot;
    android:theme=&quot;@style/AppTheme&quot;&gt;

    &lt;activity android:name=&quot;.MainActivity&quot;&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
            &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
        &lt;/intent-filter&gt;
    &lt;/activity&gt;
    &lt;service
        android:name=&quot;com.softniels.autostartonboot.ForegroundService&quot;
        android:label=&quot;My Service&quot;&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;com.softniels.autostartonboot.ForegroundService&quot; /&gt;
        &lt;/intent-filter&gt;
    &lt;/service&gt;

    &lt;receiver
        android:name=&quot;.StartMyServiceAtBootReceiver&quot;
        android:enabled=&quot;true&quot;
        android:exported=&quot;true&quot;&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot; /&gt;
            &lt;action android:name=&quot;android.intent.action.QUICKBOOT_POWERON&quot; /&gt;
        &lt;/intent-filter&gt;
    &lt;/receiver&gt;

&lt;/application&gt;

</manifest>

Here the part that doesn't run on 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(&quot;onReceive&quot;, &quot;call onReceive ACTION_BOOT_COMPLETED&quot;);
            Intent i = new Intent(context, MainActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
        }
    }
}

答案1

得分: 20

我知道这可能有点旧,但我面临了同样的问题,根据这个链接:

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秒)

如果其他人也遇到这个问题,可以将这个留在这里。这仅适用于 Android 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;
        }
英文:

I know that this may be old but I have faced the same problem and according to this:
https://developer.android.com/guide/components/activities/background-starts

The easiest solution I came up with was simply adding

    &lt;uses-permission android:name=&quot;android.permission.SYSTEM_ALERT_WINDOW&quot;/&gt;

And setting up the receiver:

&lt;receiver
android:name=&quot;.BootReceiver&quot;&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot; /&gt;
        &lt;/intent-filter&gt;
    &lt;/receiver&gt;

To the manifest.

Receiver code:

@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);
    }
}

Both options work. The only downside I see is that it takes rather a while for app to load (can be up to 10 seconds from my testings)

Leaving this here for other people if they encounter this as well.
This only applies to android 10 and up. There is a need to request "Display over other apps" permission

This requires drawing overlay, which can be done with:

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

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

答案2

得分: 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 + ")");
            // 需要安排一个服务来执行
            JobServiceScheduler jobServiceScheduler = new JobServiceScheduler(context);
            boolean result = jobServiceScheduler.scheduleMainService(20L); // 等待启动的时间
        } else {
            Log.e(TAG, "launching from normal < API 29");
            // 仍然可以启动一个活动
            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 seconds) {
        ComponentName serviceComponent = new ComponentName(context, YourService.class);
        JobInfo.Builder builder = getCommonBuilder(serviceComponent, YOUR_SERVICE_JOB_ID);
        builder.setMinimumLatency(TimeUnit.SECONDS.toMillis(seconds / 2)); // 最少等待时间
        builder.setOverrideDeadline(TimeUnit.SECONDS.toMillis(seconds)); // 最大延迟时间
        PersistableBundle extras = new PersistableBundle();
        extras.putLong("time", seconds);
        builder.setExtras(extras);

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

Guess I found a 'solution' for me.

    public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
            if (Build.VERSION.SDK_INT &gt; Build.VERSION_CODES.P) {
                Log.e(TAG, &quot;launching from special &gt; API 28 (&quot; + Build.VERSION.SDK_INT + &quot;)&quot;); // 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, &quot;launching from normal &lt; API 29&quot;); // 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 &lt; 28) {
                        context.startService(intentMain);
                    } else {
                        context.startForegroundService(intentMain);
                    }
                } catch (ActivityNotFoundException ex) {
                    Log.e(TAG, &quot;ActivityNotFoundException&quot; + 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(&quot;time&quot;, segundos);
        builder.setExtras(extras);

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

答案3

得分: 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());
    }
}
英文:

context.startActivity() is not launching, I solved it the following way:

  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 &gt;= Build.VERSION_CODES.M) {
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
} else if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {
mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}

答案4

得分: 0

我在清单文件中使用了以下权限来解决这个问题:

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

在主活动中:

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

正确的导入设置是:android.provider。

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

以下是文档:

`boot_completed` 在 Android 10(API 级别 29)上无法正常工作。

英文:

I solved it with this permission in the manifest:

&lt;uses-permission android:name=&quot;android.permission.SYSTEM_ALERT_WINDOW&quot;/&gt; 

And in the main activity :

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

The correct import for Settings is:android.provider

The first time the app boots the permission will be prompted for controlling which apps can draw on top of other apps, the next device will start the application will boot up using the typical broadcast receiver.

Here is the doc

`boot_completed` 在 Android 10(API 级别 29)上无法正常工作。

huangapple
  • 本文由 发表于 2020年3月16日 09:08:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/60699244.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定