一、应用场景
1、声网集成聊天室,锁屏或者后台,手机采集声音异常。对方听不到本人说话。
原因是:Android 9 设备,应用锁屏或切后台后一分钟内音频采集无效。从 Android 官网来看,这是系统强制限制。原文如下:
Limited access to sensors in background
Android 9 limits the ability for background apps to access user input and sensor data. If your app is running in the background on a device running Android 9, the system applies the following restrictions to your app:
- Your app cannot access the microphone or camera.
- Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don’t receive events.
- Sensors that use the on-change or one-shot reporting modes don’t receive events. If your app needs to detect sensor events on devices
running Android 9, use a foreground service.
详见 Android 行为变更。
2、解决方案: 目前 Android 官网没有明确说明后台采集声音或视频应如何处理,但使用前台服务可以让应用正常工作。
如果 Android 9 设备用户有锁屏后采集音频或视频的需求,可以在锁屏或退至后台前起一个 Service,并在退出锁屏或返回前台前终止 Service。
二、解决办法
1、监听app锁屏或切后台,以及切换到前台
我们这里直接贴出代码,具体的可以参考这篇文章:监听app锁屏或切后台,以及切换到前台
import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
/**
* Describe: 监听app锁屏或切后台
* Created by Gao Chunfa on 2020/3/19.
* Company: Hainan DaDi(Jinan) Network Technology Co. Ltd
*/
class ActivityLifecycleListener implements Application.ActivityLifecycleCallbacks {
private int activityCount = 0;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
activityCount++;
getAppStatus();
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
activityCount--;
getAppStatus();
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
/**
* 根据activityCount,判断app状态
*/
public void getAppStatus() {
if (activityCount == 0) {
//App进入后台或者APP锁屏了
//开启服务
} else {
//App进入前台
//结束服务
}
}
}
2、创建前台服务
在Android 8.0 中谷歌对后台service进行了严格限制,不允许默默无闻的后台service存在,若想用service,必须以startForegroundService的方式启动service,对所启动Service进行通知处理(Google对Android8.0之后进行的强制处理),并且必须在service内部5s内执行startForeground方法显示一个前台通知,否则会产生ANR或者crash。
因此我们需要在启动服务的地方根据版本判断是调用startForegroundService()或者startService()函数;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//android8.0以上通过startForegroundService启动service
startForegroundService(new Intent(MainActivity.this,MyService.class));
}else{
startService(new Intent(MainActivity.this, MyService.class));
}
同时注意:应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。
因此我们在创建服务后,在onCreate()方法中调用该方法(startForeground)
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
startForeground(1,notification());
}
}
服务的全部代码如下:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import net.liexiang.dianjing.R;
/**
* Describe: app后台后启动一个服务
* Created by Gao Chunfa on 2020/3/19.
* Company: Hainan DaDi(Jinan) Network Technology Co. Ltd
*/
public class KeepAppLifeService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private NotificationManager notificationManager;
private String notificationId = "keep_app_live";
private String notificationName = "APP后台运行中";
@Override
public void onCreate() {
super.onCreate();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//创建NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
//不震动
channel.enableVibration(false);
//静音
channel.setSound(null, null);
notificationManager.createNotificationChannel(channel);
}
//创建服务后,五秒内调用该方法
startForeground(1, getNotification());
}
/**
* 获取通知(Android8.0后需要)
* @return
*/
private Notification getNotification() {
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_logo)
.setContentTitle("伙玩")
.setContentIntent(getIntent())
.setContentText("后台运行中");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(notificationId);
}
return builder.build();
}
/**
* 点击后,直接打开app(之前的页面),不跳转特定activity
* @return
*/
private PendingIntent getIntent() {
Intent msgIntent = getApplicationContext().getPackageManager().getLaunchIntentForPackage(getPackageName());//获取启动Activity
PendingIntent pendingIntent = PendingIntent.getActivity(
getApplicationContext(),
1,
msgIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
}
注意:
如果想通知栏点击后,直接打开app(之前的页面),不跳转特定activity
需要在启动Activity中的onCreate方法中加上如下代码
否则每次home键都会回到首页
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isTaskRoot()) {
finish();
return;
}
}
大功告成~~