安卓 12 为什么无法通过广播方式开启另一个应用?

我想实现的功能是注册广播,然后广播中的onReceive收到广播数据后直接开启另一个应用.
我试了一下,在安卓9中可以收到广播后打开另一个应用,但是安卓12上面却无法打开应用,该如何在安卓12或以上也能正常打开呢?

package com.example.launcherdemo;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;

import com.blankj.utilcode.util.LogUtils;
import com.example.launcherdemo.bean.ActionBean;
import com.example.launcherdemo.other.DynamicServiceImpl;
import com.google.gson.Gson;
import com.jeremyliao.liveeventbus.LiveEventBus;

/**
 * date:        2025/3/31 星期一
 * author:      Bill
 * describe:
 */
public class AReceiver extends BroadcastReceiver {

    private static final String TAG = "AReceiver";
    private String otherPackageName="com.example.demob";//要开启的应用包名

    //和清单文件注册的广播action必须一致
    private static final String ACTION = "com.xzhy.ademo.ACTION_CUSTOM_BROADCAST_B";
    private static final String EXTRA_MESSAGE = "message";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ACTION.equals(action)) {

//            String packageName = "com.example.demob";
//            String className = "com.example.demob.MainActivity";
//
//            Intent launchIntent = new Intent();
//            launchIntent.setComponent(new ComponentName(packageName, className));
//            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须添加此 Flag
//
//            try {
//                context.startActivity(launchIntent);
//            } catch (ActivityNotFoundException e) {
//                // 处理目标应用未安装的情况
//                Log.e("MyReceiver", "Target app not found", e);
//            }

            String json = intent.getStringExtra(EXTRA_MESSAGE);
            Toast.makeText(context, "收到广播 1738 message=" + json, Toast.LENGTH_SHORT).show();
//            Log.d("AReceiver", "--- AReceiver onReceive message: "+message);
            //todo: 解析并操作接收到的JSON数据
            Gson gson = new Gson();
            ActionBean bean = gson.fromJson(json, ActionBean.class);
            String autoAction = bean.getData().getAction(); //获取并解析自动操作数据

            Log.d("1602", "动作= " + autoAction);
//            new DynamicServiceImpl(context).processEncodedData(json);
            switch (autoAction) {
                case "OPEN_APP":    //开启应用
                    LogUtils.d("1629 111111111111");
                    launch(context);
                    break;
            }
        }
    }

    private void launch(Context context) {
        //调起微信
        String weChatPackageName = "com.tencent.mm";
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ComponentName cn = new ComponentName(weChatPackageName, "com.tencent.mm.ui.LauncherUI");
        intent.setComponent(cn);
        context.startActivity(intent);

    }

}
阅读 281
1 个回答

确实,Android 12开始对后台启动应用有了更严格的限制,这就是为什么同样的代码在Android 9上正常,到了12却不行了。

我建议你试试这几种方法:

首先,最直接的办法是用PendingIntent:

private void launch(Context context) {
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    ComponentName cn = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.LauncherUI");
    intent.setComponent(cn);
    
    // 这里用PendingIntent可能会更友好些
    PendingIntent pendingIntent = PendingIntent.getActivity(
        context, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
    
    try {
        pendingIntent.send();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

或者你也可以考虑用通知的方式引导用户点击启动:

private void launchViaNotification(Context context) {
    // 创建一个通知,让用户点击启动目标应用
    // 这种方式用户体验可能更好,且通过率更高
}

别忘了在清单文件中加上:

<queries>
    <package android:name="com.tencent.mm" />
    <package android:name="com.example.demob" />
</queries>

说实话,Android从11开始就对这种"偷偷"启动其他应用的行为越来越严格了。如果是内部测试用的APP,你可以尝试上面的办法;如果是要上架的,建议考虑改变交互方式,让用户主动去点击启动,这样成功率会高很多。

你试试看,有问题随时问我哈!


通知模式可以参考一下示例

首先,确保引入这些包:

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import android.Manifest;
import android.content.pm.PackageManager;

然后在AReceiver类中添加以下方法:

private void launchViaNotification(Context context) {
    // 创建通知渠道(Android 8.0及以上需要)
    String channelId = "app_launch_channel";
    String channelName = "App Launch";
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(
                channelId,
                channelName,
                NotificationManager.IMPORTANCE_HIGH);
        NotificationManager notificationManager = 
                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);
    }
    
    // 准备启动意图 - 使用你想启动的应用包名
    Intent launchIntent = new Intent(Intent.ACTION_MAIN);
    launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    ComponentName cn = new ComponentName(otherPackageName, 
            otherPackageName + ".MainActivity"); // 使用正确的主活动
    launchIntent.setComponent(cn);
    
    // 创建PendingIntent
    PendingIntent pendingIntent = PendingIntent.getActivity(
            context, 
            0, 
            launchIntent, 
            PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
    
    // 构建通知
    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(android.R.drawable.ic_dialog_info) // 使用系统图标或你自己的
            .setContentTitle("打开应用")
            .setContentText("点击此通知打开" + otherPackageName)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true);
    
    // 显示通知
    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
    
    // 检查通知权限(Android 13及以上需要)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) 
                != PackageManager.PERMISSION_GRANTED) {
            // 如果没有权限,只能给出提示
            Toast.makeText(context, "需要通知权限才能启动应用", Toast.LENGTH_LONG).show();
            return;
        }
    }
    
    try {
        notificationManager.notify(100, builder.build());
        Log.d(TAG, "通知已发送,等待用户点击启动应用");
    } catch (Exception e) {
        Log.e(TAG, "发送通知失败", e);
    }
}

最后,修改onReceive方法中的相关代码:

switch (autoAction) {
    case "OPEN_APP":    //开启应用
        LogUtils.d("1629 尝试通过通知打开应用");
        // 改用通知方式启动
        launchViaNotification(context);
        break;
}

别忘了在AndroidManifest.xml中添加以下权限:

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

如果你的目标是Android 12及以上版本,还需要在AndroidManifest.xml的<queries>标签中声明要访问的包:

<queries>
    <package android:name="com.example.demob" />
    <package android:name="com.tencent.mm" />
</queries>

这样,当广播接收器接收到广播时,它将创建一个通知,用户点击通知后才会启动目标应用。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题