新后台任务
This commit is contained in:
2
android/.idea/gradle.xml
generated
2
android/.idea/gradle.xml
generated
@@ -27,14 +27,12 @@
|
|||||||
<option value="$PROJECT_DIR$/../node_modules/@react-native-cookies/cookies/android" />
|
<option value="$PROJECT_DIR$/../node_modules/@react-native-cookies/cookies/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/@react-native-ml-kit/barcode-scanning/android" />
|
<option value="$PROJECT_DIR$/../node_modules/@react-native-ml-kit/barcode-scanning/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/@react-native/gradle-plugin" />
|
<option value="$PROJECT_DIR$/../node_modules/@react-native/gradle-plugin" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-background-actions/android" />
|
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-device-info/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-device-info/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-fs/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-fs/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-gesture-handler/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-gesture-handler/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-safe-area-context/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-safe-area-context/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-screens/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-screens/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-svg/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-svg/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-tcp-socket/android" />
|
|
||||||
<option value="$PROJECT_DIR$/../node_modules/react-native-webview/android" />
|
<option value="$PROJECT_DIR$/../node_modules/react-native-webview/android" />
|
||||||
<option value="$PROJECT_DIR$/../node_modules/rnwalletman/android" />
|
<option value="$PROJECT_DIR$/../node_modules/rnwalletman/android" />
|
||||||
</set>
|
</set>
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-native": "0.72.10",
|
"react-native": "0.72.10",
|
||||||
"react-native-animatable": "^1.4.0",
|
"react-native-animatable": "^1.4.0",
|
||||||
"react-native-background-actions": "^4.1.0",
|
|
||||||
"react-native-device-info": "14.0.4",
|
"react-native-device-info": "14.0.4",
|
||||||
"react-native-fs": "^2.20.0",
|
"react-native-fs": "^2.20.0",
|
||||||
"react-native-gesture-handler": "~2.9.0",
|
"react-native-gesture-handler": "~2.9.0",
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
"react-native-screens": "~3.36.0",
|
"react-native-screens": "~3.36.0",
|
||||||
"react-native-svg": "^14.1.0",
|
"react-native-svg": "^14.1.0",
|
||||||
"react-native-svg-transformer": "^1.5.3",
|
"react-native-svg-transformer": "^1.5.3",
|
||||||
"react-native-tcp-socket": "^6.4.1",
|
|
||||||
"react-native-webview": "13.6.2",
|
"react-native-webview": "13.6.2",
|
||||||
"rnwalletman": "./libs/rnwalletman"
|
"rnwalletman": "./libs/rnwalletman"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
diff --git a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/BackgroundTaskOptions.java b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/BackgroundTaskOptions.java
|
|
||||||
index 35d8f87..175cab1 100644
|
|
||||||
--- a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/BackgroundTaskOptions.java
|
|
||||||
+++ b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/BackgroundTaskOptions.java
|
|
||||||
@@ -24,25 +24,21 @@ public final class BackgroundTaskOptions {
|
|
||||||
}
|
|
||||||
|
|
||||||
public BackgroundTaskOptions(@NonNull final ReactContext reactContext, @NonNull final ReadableMap options) {
|
|
||||||
- // Create extras
|
|
||||||
extras = Arguments.toBundle(options);
|
|
||||||
if (extras == null)
|
|
||||||
throw new IllegalArgumentException("Could not convert arguments to bundle");
|
|
||||||
- // Get taskTitle
|
|
||||||
try {
|
|
||||||
if (options.getString("taskTitle") == null)
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("Task title cannot be null");
|
|
||||||
}
|
|
||||||
- // Get taskDesc
|
|
||||||
try {
|
|
||||||
if (options.getString("taskDesc") == null)
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("Task description cannot be null");
|
|
||||||
}
|
|
||||||
- // Get iconInt
|
|
||||||
try {
|
|
||||||
final ReadableMap iconMap = options.getMap("taskIcon");
|
|
||||||
if (iconMap == null)
|
|
||||||
@@ -55,7 +51,6 @@ public final class BackgroundTaskOptions {
|
|
||||||
if (iconPackage == null)
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
} catch (Exception e) {
|
|
||||||
- // Get the current package as default
|
|
||||||
iconPackage = reactContext.getPackageName();
|
|
||||||
}
|
|
||||||
final int iconInt = reactContext.getResources().getIdentifier(iconName, iconType, iconPackage);
|
|
||||||
@@ -65,7 +60,6 @@ public final class BackgroundTaskOptions {
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("Task icon not found");
|
|
||||||
}
|
|
||||||
- // Get color
|
|
||||||
try {
|
|
||||||
final String color = options.getString("color");
|
|
||||||
extras.putInt("color", Color.parseColor(color));
|
|
||||||
@@ -114,7 +108,6 @@ public final class BackgroundTaskOptions {
|
|
||||||
try {
|
|
||||||
types = extras.getStringArrayList("foregroundServiceType");
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
- // If the stored value is not an ArrayList<String>, treat it as no types.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (types == null) {
|
|
||||||
@@ -156,31 +149,6 @@ public final class BackgroundTaskOptions {
|
|
||||||
return ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
- case "health":
|
|
||||||
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
||||||
- return ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH;
|
|
||||||
- }
|
|
||||||
- return 0;
|
|
||||||
- case "remoteMessaging":
|
|
||||||
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
||||||
- return ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING;
|
|
||||||
- }
|
|
||||||
- return 0;
|
|
||||||
- case "systemExempted":
|
|
||||||
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
||||||
- return ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED;
|
|
||||||
- }
|
|
||||||
- return 0;
|
|
||||||
- case "shortService":
|
|
||||||
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
||||||
- return ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
|
|
||||||
- }
|
|
||||||
- return 0;
|
|
||||||
- case "specialUse":
|
|
||||||
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
||||||
- return ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;
|
|
||||||
- }
|
|
||||||
- return 0;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
diff --git a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
|
||||||
index 963b788..b75c098 100644
|
|
||||||
--- a/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
|
||||||
+++ b/node_modules/react-native-background-actions/android/src/main/java/com/asterinet/react/bgactions/RNBackgroundActionsTask.java
|
|
||||||
@@ -5,6 +5,7 @@ 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.net.Uri;
|
|
||||||
@@ -14,21 +15,22 @@ import android.os.Bundle;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
-import androidx.core.app.ServiceCompat;
|
|
||||||
|
|
||||||
import com.facebook.react.HeadlessJsTaskService;
|
|
||||||
import com.facebook.react.bridge.Arguments;
|
|
||||||
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
|
|
||||||
|
|
||||||
+import java.lang.reflect.Method;
|
|
||||||
+
|
|
||||||
final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
|
||||||
|
|
||||||
public static final int SERVICE_NOTIFICATION_ID = 92901;
|
|
||||||
private static final String CHANNEL_ID = "RN_BACKGROUND_ACTIONS_CHANNEL";
|
|
||||||
+ private static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1;
|
|
||||||
|
|
||||||
@SuppressLint("UnspecifiedImmutableFlag")
|
|
||||||
@NonNull
|
|
||||||
public static Notification buildNotification(@NonNull Context context, @NonNull final BackgroundTaskOptions bgOptions) {
|
|
||||||
- // Get info
|
|
||||||
final String taskTitle = bgOptions.getTaskTitle();
|
|
||||||
final String taskDesc = bgOptions.getTaskDesc();
|
|
||||||
final int iconInt = bgOptions.getIconInt();
|
|
||||||
@@ -38,7 +40,6 @@ final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
|
||||||
if (linkingURI != null) {
|
|
||||||
notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(linkingURI));
|
|
||||||
} else {
|
|
||||||
- //as RN works on single activity architecture - we don't need to find current activity on behalf of react context
|
|
||||||
notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
|
|
||||||
if (notificationIntent == null) {
|
|
||||||
notificationIntent = new Intent(Intent.ACTION_MAIN)
|
|
||||||
@@ -46,13 +47,11 @@ final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
|
||||||
.setPackage(context.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- final PendingIntent contentIntent;
|
|
||||||
int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
- // IMMUTABLE is available and recommended from API 23+
|
|
||||||
pendingIntentFlags |= PendingIntent.FLAG_IMMUTABLE;
|
|
||||||
}
|
|
||||||
- contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, pendingIntentFlags);
|
|
||||||
+ final PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, pendingIntentFlags);
|
|
||||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
|
||||||
.setContentTitle(taskTitle)
|
|
||||||
.setContentText(taskDesc)
|
|
||||||
@@ -93,21 +92,22 @@ final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
|
||||||
throw new IllegalArgumentException("Extras cannot be null");
|
|
||||||
}
|
|
||||||
final BackgroundTaskOptions bgOptions = new BackgroundTaskOptions(extras);
|
|
||||||
- createNotificationChannel(bgOptions.getTaskTitle(), bgOptions.getTaskDesc()); // Necessary creating channel for API 26+
|
|
||||||
- // Create the notification
|
|
||||||
+ createNotificationChannel(bgOptions.getTaskTitle(), bgOptions.getTaskDesc());
|
|
||||||
final Notification notification = buildNotification(this, bgOptions);
|
|
||||||
|
|
||||||
try {
|
|
||||||
- ServiceCompat.startForeground(
|
|
||||||
- this,
|
|
||||||
- SERVICE_NOTIFICATION_ID,
|
|
||||||
- notification,
|
|
||||||
- bgOptions.getForegroundServiceType()
|
|
||||||
- );
|
|
||||||
+ int fgType = bgOptions.getForegroundServiceType();
|
|
||||||
+ if (fgType == 0) {
|
|
||||||
+ fgType = FOREGROUND_SERVICE_TYPE_DATA_SYNC;
|
|
||||||
+ }
|
|
||||||
+ if (Build.VERSION.SDK_INT >= 34) {
|
|
||||||
+ startForegroundWithType(SERVICE_NOTIFICATION_ID, notification, fgType);
|
|
||||||
+ } else {
|
|
||||||
+ startForeground(SERVICE_NOTIFICATION_ID, notification);
|
|
||||||
+ }
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
|
||||||
&& e instanceof android.app.ForegroundServiceStartNotAllowedException) {
|
|
||||||
- // Android 12+: not allowed to start foreground service from background
|
|
||||||
stopSelf(startId);
|
|
||||||
return START_NOT_STICKY;
|
|
||||||
}
|
|
||||||
@@ -116,16 +116,13 @@ final public class RNBackgroundActionsTask extends HeadlessJsTaskService {
|
|
||||||
return super.onStartCommand(intent, flags, startId);
|
|
||||||
}
|
|
||||||
|
|
||||||
- @Override
|
|
||||||
- public void onTimeout(int startId) {
|
|
||||||
- super.onTimeout(startId);
|
|
||||||
- stopSelf(startId);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- @Override
|
|
||||||
- public void onTimeout(int startId, int fgsType) {
|
|
||||||
- super.onTimeout(startId, fgsType);
|
|
||||||
- stopSelf(startId);
|
|
||||||
+ private void startForegroundWithType(int id, Notification notification, int fgType) {
|
|
||||||
+ try {
|
|
||||||
+ Method method = Service.class.getMethod("startForeground", int.class, Notification.class, int.class);
|
|
||||||
+ method.invoke(this, id, notification, fgType);
|
|
||||||
+ } catch (Exception e) {
|
|
||||||
+ throw new RuntimeException("Failed to start foreground service with type", e);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createNotificationChannel(@NonNull final String taskTitle, @NonNull final String taskDesc) {
|
|
||||||
@@ -257,8 +257,19 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async ensureBatteryOptimizationIgnored() {
|
||||||
|
if (Platform.OS !== 'android') return;
|
||||||
|
try {
|
||||||
|
const mod = NativeModules.ProxyServiceModule;
|
||||||
|
if (!mod) return;
|
||||||
|
const ignored = await mod.isBatteryOptimizationIgnored();
|
||||||
|
if (!ignored) await mod.requestIgnoreBatteryOptimization();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
async startProxyClient() {
|
async startProxyClient() {
|
||||||
try {
|
try {
|
||||||
|
await this.ensureBatteryOptimizationIgnored();
|
||||||
this.clientId = DeviceInfo.getUniqueIdSync();
|
this.clientId = DeviceInfo.getUniqueIdSync();
|
||||||
const userId = Api.instance.getUserId();
|
const userId = Api.instance.getUserId();
|
||||||
this.setState({ proxyStatus: 'connecting' });
|
this.setState({ proxyStatus: 'connecting' });
|
||||||
@@ -268,12 +279,17 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
);
|
);
|
||||||
proxyBackgroundService.setTokenAutoRebindEnabled(this.state.tokenAutoRebind);
|
proxyBackgroundService.setTokenAutoRebindEnabled(this.state.tokenAutoRebind);
|
||||||
await proxyBackgroundService.start({
|
await proxyBackgroundService.start({
|
||||||
wsUrl: Api.WS_URL, clientId: this.clientId || '', userId,
|
wsUrl: Api.WS_URL,
|
||||||
debug: true, heartbeatInterval: 10000, reconnectInterval: 5000, reconnectMaxAttempts: Infinity,
|
clientId: this.clientId || '',
|
||||||
|
userId,
|
||||||
|
heartbeatInterval: 10000,
|
||||||
|
reconnectInterval: 5000,
|
||||||
|
reconnectMaxAttempts: Infinity,
|
||||||
onConnected: () => this.setState({ proxyStatus: 'connected' }),
|
onConnected: () => this.setState({ proxyStatus: 'connected' }),
|
||||||
onDisconnected: () => this.setState({ proxyStatus: 'disconnected' }),
|
onDisconnected: () => this.setState({ proxyStatus: 'disconnected' }),
|
||||||
onError: (error: string) => this.setState({ proxyStatus: 'error', proxyError: error }),
|
onError: (error: string) => this.setState({ proxyStatus: 'error', proxyError: error }),
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Proxy] init failed:', error);
|
console.error('[Proxy] init failed:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user