适配Android14对截屏的严格要求

This commit is contained in:
Chen Guangming
2024-05-14 21:44:51 +08:00
parent 04277eda04
commit 8da1ee6a6a
6 changed files with 37 additions and 10 deletions

View File

@@ -122,6 +122,8 @@
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<!-- Property "largeHeap" is not recommended to set to true. -->
<!-- https://stackoverflow.com/questions/27396892/what-are-advantages-of-setting-largeheap-to-true -->
<application

View File

@@ -6,6 +6,7 @@ import android.content.Intent;
import android.media.projection.MediaProjectionManager;
import org.autojs.autojs.app.OnActivityResultDelegate;
import org.autojs.autojs.util.ForegroundServiceUtils;
/**
* Created by Stardust on May 17, 2017.
@@ -46,9 +47,18 @@ public interface ScreenCaptureRequester {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mResult = data;
mMediator.removeDelegate(this);
onResult(resultCode, data);
}
// 按照官方文档https://developer.android.com/reference/android/media/projection/MediaProjectionManager启动媒体投影的示例流程如下
// 1. AndroidManifest.xml声明mediaProjection类型前台服务
// 2. 通过调用MediaProjectionManager#createScreenCaptureIntent()创建intent并传递给Activity#startActivityForResult(Intent, int)
// 3. 在得到用户授权后回调Activity#onActivityResult中使用 ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION类型 启动前台服务
// 4. 再通过MediaProjectionManager#getMediaProjection(int, Intent)得到MediaProjection
// 5. 通过MediaProjection#createVirtualDisplay调用启动媒体投影的屏幕捕获会话
// 总结就是,要保证:先授权,再启动服务,再录屏的顺序
// 原代码在ScreenCaptureRequesterImpl#requst中startService会有时序问题此时用户还没授权完成时Android 14+启动前台服务实测会崩溃
// 改成bindService并等待onServiceConnected回调
ForegroundServiceUtils.requestReadyIfNeeded(mActivity.getApplicationContext(), ScreenCapturerForegroundService.class, () -> onResult(resultCode, data));
}
}
abstract class AbstractScreenCaptureRequester implements ScreenCaptureRequester {
@@ -75,7 +85,5 @@ public interface ScreenCaptureRequester {
if (mCallback != null)
mCallback.onRequestResult(Activity.RESULT_CANCELED, null);
}
}
}

View File

@@ -4,7 +4,6 @@ import android.app.Activity;
import org.autojs.autojs.AbstractAutoJs;
import org.autojs.autojs.app.OnActivityResultDelegate;
import org.autojs.autojs.util.ForegroundServiceUtils;
public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractScreenCaptureRequester {
@@ -25,8 +24,6 @@ public class ScreenCaptureRequesterImpl extends ScreenCaptureRequester.AbstractS
@Override
public void request() {
ForegroundServiceUtils.requestIfNeeded(mAutoJs.getApplicationContext(), ScreenCapturerForegroundService.class);
Activity activity = mAutoJs.getAppUtils().getCurrentActivity();
if (activity instanceof OnActivityResultDelegate.DelegateHost) {

View File

@@ -4,6 +4,7 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -38,7 +39,7 @@ public class ScreenCapturerForegroundService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
return new Binder();
}
private void startForeground() {

View File

@@ -33,7 +33,7 @@ class MainActivityForegroundService : Service() {
.create()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
ForegroundServiceUtils.startForeground(foregroundServiceCreator, ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED)
ForegroundServiceUtils.startForeground(foregroundServiceCreator, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
} else {
ForegroundServiceUtils.startForeground(foregroundServiceCreator)
}

View File

@@ -6,10 +6,12 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -36,6 +38,23 @@ public class ForegroundServiceUtils {
}
}
public static void requestReadyIfNeeded(Context context, Class<?> className, Runnable runnable) {
if (isRunning(context, className)) {
runnable.run();
} else {
context.bindService(getService(context, className), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
runnable.run();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, Context.BIND_AUTO_CREATE);
}
}
public static boolean startService(Context context, Class<?> className) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return context.startForegroundService(getService(context, className)) != null;