首页 > 其他分享 >Android Q实现app开机自启

Android Q实现app开机自启

时间:2023-09-06 21:38:10浏览次数:37  
标签:false 启动 app 自启 Intent 前台 Activity Android com

开机自启动

​ 开机自启,那系统开机成功会发生什么情况,借助某些信息的产生我们可以实现开机自启吗?

​ 似乎原理就是这样子的,但是总需要考虑现实情况。现实就是首先这个app是系统app,所以这一步就排除了一大波的app,不过你要问难道不是系统应用就不行了吗,当然Android 10 以下可以一试。

BOOT_COMPLETED广播

​ 系统加载成功会发送 BOOT_COMPLETED广播,既然是广播我们自然便可以接收,注册一个广播接收器。

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

​ 同时需要申请接收广播权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
public class BootCompletedReceiver extends BroadcastReceiver {

    final String TAG = BootCompletedReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d(TAG, "onReceive: " + intent.getAction());
    }
}

​ 以上的步骤实现了在系统启动成功时接收广播并在广播接收器中处理需要的逻辑。而我们所需要的逻辑便是在这其中启动MainActivity,所以简单的startActivity似乎就能满足需求,但实际上并非如此。

直接启动Activity

​ 直接在onReceive中添加如下代码

 Intent intentOfMain = new Intent(context,MainActivity.class);
 intentOfMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 context.startActivity(intentOfMain);

​ 但在查阅log时可以发现以下问题:

08-30 16:27:21.928  1009  1467 W ActivityTaskManager: Background activity start [callingPackage: com.lzwml.selfstart; callingUid: 10110; isCallingUidForeground: false; isCallingUidPersistentSystemProcess: false; realCallingUid: 10110; isRealCallingUidForeground: false; isRealCallingUidPersistentSystemProcess: false; originatingPendingIntent: null; isBgStartWhitelisted: false; intent: Intent { flg=0x10000000 cmp=com.lzwml.selfstart/.MainActivity }; callerApp: ProcessRecord{dee5bb2 3345:com.lzwml.selfstart/u0a110}]
08-30 16:27:21.937  1009  1467 I ActivityManager: Finished processing BOOT_COMPLETED for u0
08-30 16:27:21.942  1009  1467 I ActivityManager: Killing 2773:com.android.contacts/u0a90 (adj 985): empty #17
  • callingPackage: 调用包名,即发起启动活动的应用程序包名为com.lzwml.selfstart。
  • callingUid: 调用应用程序的用户ID为10110。
  • isCallingUidForeground: 调用应用程序的用户ID是否在前台运行为false。
  • isCallingUidPersistentSystemProcess: 调用应用程序的用户ID是否是持久的系统进程为false。
  • realCallingUid: 实际调用应用程序的用户ID为10110。
  • isRealCallingUidForeground: 实际调用应用程序的用户ID是否在前台运行为false。
  • isRealCallingUidPersistentSystemProcess: 实际调用应用程序的用户ID是否是持久的系统进程为false。
  • originatingPendingIntent: 源PendingIntent,即启动活动的原始PendingIntent为null。
  • isBgStartWhitelisted: 后台启动白名单,即启动活动是否在后台启动白名单中为false。
  • intent: 意图,即启动活动的Intent为Intent { flg=0x10000000 cmp=com.lzwml.selfstart/.MainActivity },表示要启动的是com.lzwml.selfstart应用程序的MainActivity活动。

按照Google要求,在Android Q上运行的应用只有在满足以下一个或多个条件时才能启动Activity:常见的有如下几种

具有可见窗口,例如:

  1. 在前台运行的Activity。(前台服务不会将应用限定为在前台运行。)

  2. 该应用在前台任务的返回栈中具有一项 Activity。(必须同前台Activity位于同一个Task返回栈,如果两个Task栈不行。)

  3. 该应用已获得用户授予的 SYSTEM_ALERT_WINDOW 权限。

  4. pendingIntent临时白名单机制,不拦截通过通知拉起的应用。

    • 通过通知,利用pendingIntent启动 Activity。
    • 通过通知,在 PendingIntent中发送广播,接收广播后启动 Activity。
    • 通过通知,在 PendingIntent中启动 Service(一定可以启动Service),在 Service 中启动 Activity。

可以暂时的得出这样一个结论,无法开机直接拉起一个Activity,不过看一下前两个关键点,在前台运行的持久化进程。熟悉吗,非常熟悉,这不就是前台服务吗!所以我们来试着拉起一个前台服务。

直接启动前台服务

申请前台服务的权限及弹窗权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
    android:protectionLevel="appop|development|installer|pre23|setup|signature" />

在广播接收器中启动前台服务

ContextCompat.startForegroundService(context, new Intent(context, ForegroundService.class));

在前台服务中启动Activity

public class ForegroundService extends Service {

    private static final int NOTIFICATION_ID = 1;
    final static String TAG = ForegroundService.class.getSimpleName();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.d(TAG, "onStartCommand: " + "start");
        if (Build.VERSION.SDK_INT >= 26) {
            NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", 3);
            NotificationManager notificationManager = (NotificationManager) getSystemService(NotificationManager.class);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }
        Intent newActivityIntent = new Intent(this, MainActivity.class);
        newActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startForeground(NOTIFICATION_ID, new NotificationCompat.Builder(this, "channel_id")
                .setContentTitle("New Activity")
                .setContentText("Click to open update activity")
                .setSmallIcon(R.drawable.ic_notification)
                .setContentIntent(PendingIntent.getActivity(this, 0, newActivityIntent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE))
                .setAutoCancel(true)
                .build());
        Log.d("RebootForegroundService", "====> start");
        startActivity(newActivityIntent);
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }
}

只不过现实并不如我们所预料的这般,在接收到广播之时,无法创建前台服务

ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startForegroundService:1577 android.content.ContextWrapper.startForegroundService:674 android.content.ContextWrapper.startForegroundService:674 com.mediatek.omacp.message.OmacpReceiver.beginStartingService:104 com.mediatek.omacp.message.OmacpReceiver.onReceive:77 

所以意味着无法启动服务或者活动吗?除了修改底层源码逻辑还有其他办法吗?

创建线程

创建线程,在哪里创建线程呢,在onReceive中new一个线程,然后将相关的启动代码放进去,神奇的是这样子是可行的,具体的原理还有待钻研,总之,通过这种方式,可以暂时的实现开机自启活动。

标签:false,启动,app,自启,Intent,前台,Activity,Android,com
From: https://blog.51cto.com/u_16174117/7390037

相关文章

  • Android Q实现app开机自启
    开机自启动​ 开机自启,那系统开机成功会发生什么情况,借助某些信息的产生我们可以实现开机自启吗?​ 似乎原理就是这样子的,但是总需要考虑现实情况。现实就是首先这个app是系统app,所以这一步就排除了一大波的app,不过你要问难道不是系统应用就不行了吗,当然Android10以下可以一试......
  • Android Q实现app开机自启
    开机自启动​ 开机自启,那系统开机成功会发生什么情况,借助某些信息的产生我们可以实现开机自启吗?​ 似乎原理就是这样子的,但是总需要考虑现实情况。现实就是首先这个app是系统app,所以这一步就排除了一大波的app,不过你要问难道不是系统应用就不行了吗,当然Android10以下可以一试......
  • Android Q实现app开机自启
    开机自启动​ 开机自启,那系统开机成功会发生什么情况,借助某些信息的产生我们可以实现开机自启吗?​ 似乎原理就是这样子的,但是总需要考虑现实情况。现实就是首先这个app是系统app,所以这一步就排除了一大波的app,不过你要问难道不是系统应用就不行了吗,当然Android10以下可以一试......
  • Android Q实现app开机自启
    开机自启动​ 开机自启,那系统开机成功会发生什么情况,借助某些信息的产生我们可以实现开机自启吗?​ 似乎原理就是这样子的,但是总需要考虑现实情况。现实就是首先这个app是系统app,所以这一步就排除了一大波的app,不过你要问难道不是系统应用就不行了吗,当然Android10以下可以一试......
  • Android自定义APP字体
    使用Android设备自带的字体时:<!--在你的APP主题或者需要用到的地方的主题中设置样式--><stylename="CustomStyle"parent="AppBaseTheme"><itemname="android:textViewStyle">@style/CustomFontStyleText</item><itemname="and......
  • app备案证明需要提供md5值和公钥的解决方案
    现在app上架华为市场、小米市场、苹果市场等大型的应用商店,都需要提供国内的app备案证明。无论是安卓还是ios,都需要备案了。但是问题是备案的时候需要填写app的bundleID、公钥和MD5值这些信息?那么怎么查询apk的这些信息呢?好像app的开发工具也没有提供查询这些信息的手段。 ......
  • uniapp项目实践总结(十一)自定义网络检测组件
    导语:很多时候手机设备会突然没网,这时候就需要一个网络检测组件,在没网的时候显示提示用户,提供用户体验。目录准备工作原理分析组件实现实战演练案例展示准备工作在components新建一个q-online文件夹,并新建一个q-online.vue的组件;按照前一篇所说的页面结构,编写好预......
  • Android程序员面试技巧有哪些?这5个技巧码住
    很多Android程序员掌握的知识、技术非常过关,但是在面试的过程中不一定能完完全全地展现出来,面试效果不好极大影响着就业成功率以及薪资水平。所以大家在面试的时候,最好还是提前做做准备,掌握一些技巧更好。1、自我介绍一般面试面试,HR会让我们做一个自我介绍,但凡有一点准备的人,都会事......
  • 【异常处理】java: 无法访问org.springframework.boot.SpringApplication
    java:无法访问org.springframework.boot.SpringApplication错误的类文件:/D:/Repository/org/springframework/boot/spring-boot/3.0.5/spring-boot-3.0.5.jar!/org/springframework/boot/SpringApplication.class类文件具有错误的版本61.0,应为52.0请删除该文件......
  • android9 静默卸载应用
    需要在实现的app上加上android.uid.system和系统签名,然后执行以下方法privatevoidsilenceUninstall(StringpackageName){try{PackageManagerpm=this.getPackageManager();Method[]methods=pm!=null?pm.getClass().getDeclaredMetho......