Compare commits
2 Commits
1634953750
...
24e81ccf23
| Author | SHA1 | Date | |
|---|---|---|---|
| 24e81ccf23 | |||
| ee72a1fb3e |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
android/build
|
||||
42
android/build.gradle
Normal file
42
android/build.gradle
Normal file
@@ -0,0 +1,42 @@
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "31.0.0"
|
||||
minSdkVersion = 21
|
||||
compileSdkVersion = 31
|
||||
targetSdkVersion = 31
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.2.1")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.android.library"
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.facebook.react:react-native:+'
|
||||
}
|
||||
17
android/src/main/AndroidManifest.xml
Normal file
17
android/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.rnbot">
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".RNBotAccessibilityService"
|
||||
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.accessibilityservice"
|
||||
android:resource="@xml/accessibility_service_config" />
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
||||
160
android/src/main/java/com/rnbot/RNBotAccessibilityService.java
Normal file
160
android/src/main/java/com/rnbot/RNBotAccessibilityService.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package com.rnbot;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.accessibilityservice.GestureDescription;
|
||||
import android.graphics.Path;
|
||||
import android.os.Bundle;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RNBotAccessibilityService extends AccessibilityService {
|
||||
private static RNBotAccessibilityService instance;
|
||||
|
||||
public static RNBotAccessibilityService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static boolean isServiceRunning() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||
// 可以在这里监听各种事件
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterrupt() {
|
||||
// 服务中断
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceConnected() {
|
||||
super.onServiceConnected();
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public List<AccessibilityNodeInfo> findNodesByType(String type, String value) {
|
||||
List<AccessibilityNodeInfo> result = new ArrayList<>();
|
||||
AccessibilityNodeInfo root = getRootInActiveWindow();
|
||||
if (root == null) return result;
|
||||
|
||||
switch (type) {
|
||||
case "id":
|
||||
findNodesByIdRecursive(root, value, result);
|
||||
break;
|
||||
case "text":
|
||||
findNodesByTextRecursive(root, value, result);
|
||||
break;
|
||||
case "name":
|
||||
findNodesByNameRecursive(root, value, result);
|
||||
break;
|
||||
case "className":
|
||||
findNodesByClassNameRecursive(root, value, result);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void findNodesByIdRecursive(AccessibilityNodeInfo node, String resId, List<AccessibilityNodeInfo> result) {
|
||||
if (node == null) return;
|
||||
|
||||
String id = node.getViewIdResourceName();
|
||||
if (id != null && id.equals(resId)) {
|
||||
result.add(node);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = node.getChild(i);
|
||||
if (child != null) {
|
||||
findNodesByIdRecursive(child, resId, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findNodesByTextRecursive(AccessibilityNodeInfo node, String text, List<AccessibilityNodeInfo> result) {
|
||||
if (node == null) return;
|
||||
|
||||
CharSequence nodeText = node.getText();
|
||||
if (nodeText != null && nodeText.toString().contains(text)) {
|
||||
result.add(node);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = node.getChild(i);
|
||||
if (child != null) {
|
||||
findNodesByTextRecursive(child, text, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findNodesByNameRecursive(AccessibilityNodeInfo node, String name, List<AccessibilityNodeInfo> result) {
|
||||
if (node == null) return;
|
||||
|
||||
CharSequence desc = node.getContentDescription();
|
||||
if (desc != null && desc.toString().contains(name)) {
|
||||
result.add(node);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = node.getChild(i);
|
||||
if (child != null) {
|
||||
findNodesByNameRecursive(child, name, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findNodesByClassNameRecursive(AccessibilityNodeInfo node, String className, List<AccessibilityNodeInfo> result) {
|
||||
if (node == null) return;
|
||||
|
||||
CharSequence cls = node.getClassName();
|
||||
if (cls != null && cls.toString().equals(className)) {
|
||||
result.add(node);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = node.getChild(i);
|
||||
if (child != null) {
|
||||
findNodesByClassNameRecursive(child, className, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean clickAt(int x, int y) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.N) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Path path = new Path();
|
||||
path.moveTo(x, y);
|
||||
|
||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||
GestureDescription gesture = builder
|
||||
.addStroke(new GestureDescription.StrokeDescription(path, 0, 50))
|
||||
.build();
|
||||
|
||||
return dispatchGesture(gesture, null, null);
|
||||
}
|
||||
|
||||
public boolean setTextById(String resId, String text) {
|
||||
List<AccessibilityNodeInfo> nodes = findNodesByType("id", resId);
|
||||
if (nodes.isEmpty()) return false;
|
||||
|
||||
AccessibilityNodeInfo node = nodes.get(0);
|
||||
if (!node.isEditable()) return false;
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
|
||||
return node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
|
||||
}
|
||||
}
|
||||
220
android/src/main/java/com/rnbot/RNBotModule.java
Normal file
220
android/src/main/java/com/rnbot/RNBotModule.java
Normal file
@@ -0,0 +1,220 @@
|
||||
package com.rnbot;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.Settings;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.WritableNativeArray;
|
||||
import com.facebook.react.bridge.WritableNativeMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RNBotModule extends ReactContextBaseJavaModule {
|
||||
private final ReactApplicationContext reactContext;
|
||||
|
||||
public RNBotModule(ReactApplicationContext context) {
|
||||
super(context);
|
||||
this.reactContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNBotModule";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void requestPermission(Promise promise) {
|
||||
try {
|
||||
Activity activity = getCurrentActivity();
|
||||
if (activity == null) {
|
||||
promise.reject("NO_ACTIVITY", "Activity is null");
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||
activity.startActivity(intent);
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void isServiceEnabled(Promise promise) {
|
||||
promise.resolve(RNBotAccessibilityService.isServiceRunning());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void findNodes(String type, String value, Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
|
||||
List<AccessibilityNodeInfo> nodes = service.findNodesByType(type, value);
|
||||
WritableArray result = new WritableNativeArray();
|
||||
|
||||
for (AccessibilityNodeInfo node : nodes) {
|
||||
WritableMap map = nodeToMap(node);
|
||||
result.pushMap(map);
|
||||
}
|
||||
|
||||
promise.resolve(result);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void click(int x, int y, Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
boolean success = service.clickAt(x, y);
|
||||
promise.resolve(success);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setText(String resId, String text, Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
boolean success = service.setTextById(resId, text);
|
||||
promise.resolve(success);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void back(Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
boolean success = service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
|
||||
promise.resolve(success);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void home(Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
boolean success = service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
|
||||
promise.resolve(success);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void recents(Promise promise) {
|
||||
try {
|
||||
RNBotAccessibilityService service = RNBotAccessibilityService.getInstance();
|
||||
if (service == null) {
|
||||
promise.reject("SERVICE_NOT_RUNNING", "无障碍服务未运行");
|
||||
return;
|
||||
}
|
||||
boolean success = service.performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
|
||||
promise.resolve(success);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void openApp(String packageName, String activityName, Promise promise) {
|
||||
try {
|
||||
Activity activity = getCurrentActivity();
|
||||
if (activity == null) {
|
||||
promise.reject("NO_ACTIVITY", "Activity is null");
|
||||
return;
|
||||
}
|
||||
|
||||
PackageManager pm = activity.getPackageManager();
|
||||
Intent intent;
|
||||
|
||||
if (activityName != null && !activityName.isEmpty()) {
|
||||
// 指定 Activity
|
||||
intent = new Intent();
|
||||
intent.setClassName(packageName, activityName);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
} else {
|
||||
// 只指定包名,启动主 Activity
|
||||
intent = pm.getLaunchIntentForPackage(packageName);
|
||||
if (intent == null) {
|
||||
promise.reject("APP_NOT_FOUND", "应用未安装: " + packageName);
|
||||
return;
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
}
|
||||
|
||||
activity.startActivity(intent);
|
||||
promise.resolve(true);
|
||||
} catch (Exception e) {
|
||||
promise.reject("ERROR", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private WritableMap nodeToMap(AccessibilityNodeInfo node) {
|
||||
WritableMap map = new WritableNativeMap();
|
||||
|
||||
if (node.getText() != null) {
|
||||
map.putString("text", node.getText().toString());
|
||||
}
|
||||
if (node.getContentDescription() != null) {
|
||||
map.putString("name", node.getContentDescription().toString());
|
||||
}
|
||||
if (node.getViewIdResourceName() != null) {
|
||||
map.putString("id", node.getViewIdResourceName());
|
||||
}
|
||||
if (node.getClassName() != null) {
|
||||
map.putString("className", node.getClassName().toString());
|
||||
}
|
||||
|
||||
android.graphics.Rect bounds = new android.graphics.Rect();
|
||||
node.getBoundsInScreen(bounds);
|
||||
|
||||
WritableMap boundsMap = new WritableNativeMap();
|
||||
boundsMap.putInt("left", bounds.left);
|
||||
boundsMap.putInt("top", bounds.top);
|
||||
boundsMap.putInt("right", bounds.right);
|
||||
boundsMap.putInt("bottom", bounds.bottom);
|
||||
boundsMap.putInt("centerX", (bounds.left + bounds.right) / 2);
|
||||
boundsMap.putInt("centerY", (bounds.top + bounds.bottom) / 2);
|
||||
|
||||
map.putMap("bounds", boundsMap);
|
||||
map.putBoolean("clickable", node.isClickable());
|
||||
map.putBoolean("editable", node.isEditable());
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
24
android/src/main/java/com/rnbot/RNBotPackage.java
Normal file
24
android/src/main/java/com/rnbot/RNBotPackage.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.rnbot;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RNBotPackage implements ReactPackage {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||
List<NativeModule> modules = new ArrayList<>();
|
||||
modules.add(new RNBotModule(reactContext));
|
||||
return modules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:accessibilityEventTypes="typeAllMask"
|
||||
android:accessibilityFeedbackType="feedbackGeneric"
|
||||
android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagRetrieveInteractiveWindows|flagReportViewIds"
|
||||
android:canRetrieveWindowContent="true"
|
||||
android:canPerformGestures="true"
|
||||
android:notificationTimeout="100" />
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "rnauto",
|
||||
"version": "1.0.0",
|
||||
"description": "React Native 无障碍自动化库",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": ["react-native", "accessibility", "automation"],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react-native": "*"
|
||||
}
|
||||
}
|
||||
129
src/index.ts
Normal file
129
src/index.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
|
||||
const { RNBotModule } = NativeModules;
|
||||
|
||||
export interface NodeBounds {
|
||||
left: number;
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
}
|
||||
|
||||
export interface NodeInfo {
|
||||
text?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
className?: string;
|
||||
bounds: NodeBounds;
|
||||
clickable: boolean;
|
||||
editable: boolean;
|
||||
}
|
||||
|
||||
class RNAuto {
|
||||
private checkAndroid(): boolean {
|
||||
if (Platform.OS !== 'android') {
|
||||
console.warn('RNAuto 仅支持 Android');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 请求无障碍权限 */
|
||||
async requestPermission(): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.requestPermission();
|
||||
}
|
||||
|
||||
/** 检查服务是否运行 */
|
||||
async isServiceEnabled(): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.isServiceEnabled();
|
||||
}
|
||||
|
||||
/** 根据 ID 查找节点 */
|
||||
async id(resId: string): Promise<NodeInfo[]> {
|
||||
if (!this.checkAndroid()) return [];
|
||||
return await RNBotModule.findNodes('id', resId);
|
||||
}
|
||||
|
||||
/** 根据文本查找节点 */
|
||||
async text(text: string): Promise<NodeInfo[]> {
|
||||
if (!this.checkAndroid()) return [];
|
||||
return await RNBotModule.findNodes('text', text);
|
||||
}
|
||||
|
||||
/** 根据 ContentDescription 查找节点 */
|
||||
async name(name: string): Promise<NodeInfo[]> {
|
||||
if (!this.checkAndroid()) return [];
|
||||
return await RNBotModule.findNodes('name', name);
|
||||
}
|
||||
|
||||
/** 根据类名查找节点 */
|
||||
async className(className: string): Promise<NodeInfo[]> {
|
||||
if (!this.checkAndroid()) return [];
|
||||
return await RNBotModule.findNodes('className', className);
|
||||
}
|
||||
|
||||
/** 点击坐标 */
|
||||
async click(x: number, y: number): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.click(x, y);
|
||||
}
|
||||
|
||||
/** 点击节点 */
|
||||
async clickNode(resId: string): Promise<boolean> {
|
||||
const nodes = await this.id(resId);
|
||||
if (nodes.length > 0) {
|
||||
const { centerX, centerY } = nodes[0].bounds;
|
||||
return await this.click(centerX, centerY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 设置文本 */
|
||||
async setText(resId: string, text: string): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.setText(resId, text);
|
||||
}
|
||||
|
||||
/** 返回键 */
|
||||
async back(): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.back();
|
||||
}
|
||||
|
||||
/** Home 键 */
|
||||
async home(): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.home();
|
||||
}
|
||||
|
||||
/** 最近任务键 */
|
||||
async recents(): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.recents();
|
||||
}
|
||||
|
||||
/** 打开应用 */
|
||||
async openApp(packageName: string, activityName?: string): Promise<boolean> {
|
||||
if (!this.checkAndroid()) return false;
|
||||
return await RNBotModule.openApp(packageName, activityName || '');
|
||||
}
|
||||
|
||||
/** 延迟 */
|
||||
delay(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// 别名兼容
|
||||
fullId = this.id;
|
||||
findById = this.id;
|
||||
findByText = this.text;
|
||||
findByName = this.name;
|
||||
findByClassName = this.className;
|
||||
}
|
||||
|
||||
export default new RNAuto();
|
||||
Reference in New Issue
Block a user