Android 关于后台socket保活以及后台弹出Activity

1、后台socket保活实现
需要实现一个前台服务,并挂载在通知栏上
1.1 需要在配置文件声明权限

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

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

1.2 声明前台服务

<service android:name=".webrtc.BackgroundService"
android:exported="true"
android:foregroundServiceType="phoneCall|camera|microphone|dataSync"
android:stopWithTask="false"
android:label="@string/app_name" />

1.3 实现前台服务,将服务挂载到前台,要显示在通知栏

public class BackgroundService extends Service {
    private static final String TAG = "BackgroundService";

    private static final String CHANNEL_ID = "my_channel_id";
    private static final String ACTION_APP_ACTIVE = "Action_app_active";
    private static final int NOTIFICATION_ID = 1;

    private static BackgroundService sInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
    }

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

        if(sInstance != null) {
            return START_STICKY;
        }

        sInstance = this;

        // 创建并显示通知(将服务挂载到前台)
        Notification notification = buildNotification();
        startForeground(NOTIFICATION_ID, notification);

        connectWebsocket();
        setIncomingCallListener();

        return START_STICKY;
    }

    private void connectWebsocket() {
        SipCallManager.getInstance(this).connectWebsocket(new RegisterListener() {
            @Override
            public void RegisterResult(boolean result) {
                if(result) {
                    LogUtils.i("$$$$$$注册成功");
                }
            }
        });
    }

    private void setIncomingCallListener() {
        SipCallManager.getInstance(this).setIncomingCallListener(new SipCallManager.OnIncomingCallListener() {
            @Override
            public void onIncomingCall(JanusHandle jh, org.json.JSONObject jsep, org.json.JSONObject data) {
                new Handler(Looper.getMainLooper()).post(() -> {
                    showIncomingCall();
                });
            }
        });
    }

    private void showIncomingCall() {
        Intent intent = new Intent(BackgroundService.this, CallActivity.class);
        intent.putExtra("CallType", SipCallManager.CALL_TYPE_INCOMING);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(intent);
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "通话";
            String description = "后台接听电话这是必须的";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);

            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

    private Notification buildNotification() {

        Intent notifIntent = new Intent(this, MainActivity.class);
        notifIntent.putExtra("Notification", true);
        notifIntent.setAction(ACTION_APP_ACTIVE);
        notifIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

        int flags;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            flags = PendingIntent.FLAG_IMMUTABLE;
        } else {
            flags = 0;
        }
        flags |= PendingIntent.FLAG_UPDATE_CURRENT;

        PendingIntent pendingIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, notifIntent, flags);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.bullet_ball_glass_green_16)
                .setContentTitle("通话 服务")
                .setContentText("后台接听电话这是必须的")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(pendingIntent);

        return builder.build();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        sInstance = null;

        stopForeground(true);

        super.onDestroy();
    }

    public static boolean isReady() {
        return sInstance != null;
    }

    public static BackgroundService instance() {
        if (isReady()) return sInstance;

        throw new RuntimeException("MainService not instantiated yet");
    }


}

1.4 需要忽略电池优化 ,要弹出框提示用户同意忽略电池优化,推荐权限插件XXPermissions

implementation 'com.github.getActivity:XXPermissions:20.0'

配置文件声明权限

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


private void ignoreBatteryOptimization() {
        String packageName = getPackageName();
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (!pm.isIgnoringBatteryOptimizations(packageName)) {
            XXPermissions
                    .with(this)
                    .permission(Permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
                    .request(new OnPermissionCallback() {
                        @Override
                        public void onGranted(@NonNull List<String> list, boolean b) {
                            if(b) {
                                LogUtils.d("已忽略电池优化");
                            }
                        }
                    });
        }
    }

到此,实现了后台socket保活,可能部分机型会中断,但大部分机型都可以实现保活了

2、后台以及息屏情况下,亮屏并弹出Activity

2.1 配置文件声明权限以及要弹出的Activity

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

<activity android:name=".webrtc.CallActivity"
            android:launchMode="singleTask"
            android:turnScreenOn="true"
            android:showWhenLocked="true"
            android:resizeableActivity="true"
            android:screenOrientation="portrait"
            android:supportsPictureInPicture="true"
            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout"
            android:exported="true">

        </activity>

2.2 实现该Activity

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 解锁屏幕
        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
        KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
        keyguardLock.disableKeyguard();

        //显示在屏幕最上层
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.sip_main_layout);

2.3 最重要的一点,一定要申请 Overlay 权限
配置文件添加权限

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

private void checkAndRequestOverlayPermission() {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivity(intent);
        }
    }

2.4 在前台服务中打开Activity

private void showIncomingCall() {
        Intent intent = new Intent(BackgroundService.this, CallActivity.class);
        intent.putExtra("CallType", SipCallManager.CALL_TYPE_INCOMING);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(intent);
    }

到此,即实现了后台或者息屏情况下,弹出Activity了。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容