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了。