针对此项目需求,需要考虑的是,我打开app后应启动Launcher Activity,然后将应用栈放到后台。需要注意的是,如果时平常的Activity,那么会闪一下屏幕,这样的效果真的让人不能接受。以下是编码思路:
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
moveTaskToBack(true)
AndroidManifest中添加权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
在Activity中检查悬浮窗权限
/**
* 检查权限
*/
public static boolean hasPermissionOnActivityResult(Context context) {
if (Build.VERSION.SDK_INT == 26) {
return hasPermissionForO(context);
} else {
return Build.VERSION.SDK_INT >= 23 ? Settings.canDrawOverlays(context) : hasPermissionBelowMarshmallow(context);
}
}
private static boolean hasPermissionBelowMarshmallow(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService("appops");
Method dispatchMethod = AppOpsManager.class.getMethod("checkOp", Integer.TYPE, Integer.TYPE, String.class);
return 0 == (Integer) dispatchMethod.invoke(manager, 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName());
} catch (Exception var3) {
return false;
}
}
@RequiresApi(api = 23)
private static boolean hasPermissionForO(Context context) {
try {
WindowManager mgr = (WindowManager) context.getSystemService("window");
if (mgr == null) {
return false;
} else {
View viewToAdd = new View(context);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(0, 0, Build.VERSION.SDK_INT >= 26 ? 2038 : 2003, 24, -2);
viewToAdd.setLayoutParams(params);
mgr.addView(viewToAdd, params);
mgr.removeView(viewToAdd);
return true;
}
} catch (Exception var4) {
Log.e("FHApplication", "hasPermissionForO e:" + var4.toString());
return false;
}
}
如果没有权限,则要申请权限(跳转到悬浮窗权限设置页):
if (VERSION.SDK_INT >= 23) {
this.requestAlertWindowPermission();
}
@RequiresApi(
api = 23
)
private void requestAlertWindowPermission() {
Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION");
intent.setData(Uri.parse("package:" + this.getPackageName()));
this.startActivityForResult(intent, requestCode);
}
返回到Activity时,在onActivityResult方法中添加如下代码:
if (requestCode == requestCode) {
if (PermissionUtil.hasPermissionOnActivityResult(this)) {
//成功申请到权限
mPermissionListener.onSuccess();
} else {
//没有申请到权限
mPermissionListener.onFail();
}
}
Android 5.0开始Android开放了录屏的方法,可以直接使用。
mMediaProjectionManager =
getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
val captureIntent = mMediaProjectionManager!!.createScreenCaptureIntent()
startActivityForResult(captureIntent, REQUEST_CODE_A)
回调
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
try {
val mediaProjection =
mMediaProjectionManager!!.getMediaProjection(resultCode, data!!)
if (mediaProjection == null) {
Toast.makeText(this, "程序发生错误:MediaProjection@1", Toast.LENGTH_SHORT).show()
return
}
mScreenRecord = ScreenRecord(this, mediaProjection)
mScreenRecord.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
ScreenRecord是个线程,在里面继续处理:
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
"ScreenRecord",
width, height, dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
//编码器创建的Surface对象,API>=18时支持:codec.createInputSurface()
getVideoEncoder()!!.inputSurface,
null,
null
)
推流过程不是重点,略过。。。
mMediaProjection.createVirtualDisplay的调用在Android 8.0及以上必须要在前台线程中进行,否则会报异常。需声明
<service
android:name=".view.PushStreamService"
android:priority="1000"
android:exported="false"
android:enabled="true"
android:foregroundServiceType="mediaProjection">
</service>
重点时最后一行。
Android 提供了MediaRecorder来帮助录屏(不仅仅支持录屏,还可以录制摄像头视频),可以同时录制音视频。网上的教程很多,不再赘述。
Android提供了ImageReader可以使用。
ImageReader imageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 2);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable (ImageReader reader){
Image image = reader.acquireNextImage();
//这里做一些其他处理
...
//最后必须close掉拿到的image
image.close();
}
},new Handler(Looper.getMainLooper()));
以上可以定义一个ImageReader来接收数据,但还需将ImageReader的Surface交给VirtualDisplay:
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
"ScreenRecord",
width, height, dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
imageReader.getSurface(), //这里是重点
null,
null
)
备注: