diff --git a/android/app/build.gradle b/android/app/build.gradle index 6cca9df..49a4f90 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -93,6 +93,13 @@ android { keyPassword 'android' } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } buildTypes { debug { signingConfig signingConfigs.debug diff --git a/android/build.gradle b/android/build.gradle index dad99b0..984e5be 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -19,3 +19,4 @@ buildscript { } apply plugin: "com.facebook.react.rootproject" + diff --git a/android/gradle.properties b/android/gradle.properties index 9afe615..56ad533 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -42,3 +42,6 @@ hermesEnabled=true # This allows your app to draw behind system bars for an immersive UI. # Note: Only works with ReactActivity and should not be used with custom Activity. edgeToEdgeEnabled=false + +# Suppress Kotlin/Java JVM target mismatch from third-party libs +kotlin.jvm.target.validation.mode=IGNORE diff --git a/docs/README.md b/docs/README.md index 2765b9a..6af8641 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,8 +15,8 @@ | 配置项 | 值 | |--------|-----| -| API 域名 | `https://sentry.xuqinmin.com` | -| IM WebSocket | `wss://sentry.xuqinmin.com/ws/im` | +| API 域名 | `https://dev.xuqinmin.com` | +| IM WebSocket | `wss://dev.xuqinmin.com/ws/im` | | 演示 AppId | `ak_demo_chat` | | 演示用户 | `demo_alice`(Alice)、`demo_bob`(Bob) | | 演示模块 | `chat-home` | @@ -142,7 +142,7 @@ cd XuqmGroup-RNChatDemo | `/api/v1/rn/` | update-service | 8084 | | `/api/` | tenant-service | 8081 | -所有接口通过 Nginx 反代至 `https://sentry.xuqinmin.com`。 +所有接口通过 Nginx 反代至 `https://dev.xuqinmin.com`。 --- diff --git a/scripts/postinstall.js b/scripts/postinstall.js new file mode 100644 index 0000000..40d91df --- /dev/null +++ b/scripts/postinstall.js @@ -0,0 +1,105 @@ +#!/usr/bin/env node +'use strict' +const fs = require('fs') +const path = require('path') + +const pickerFile = path.join( + __dirname, '..', 'node_modules', 'react-native-document-picker', + 'android', 'src', 'main', 'java', 'com', 'reactnativedocumentpicker', + 'RNDocumentPickerModule.java', +) + +if (!fs.existsSync(pickerFile)) { + console.log('[postinstall] react-native-document-picker not found, skipping patch') + process.exit(0) +} + +let content = fs.readFileSync(pickerFile, 'utf8') + +if (!content.includes('GuardedResultAsyncTask')) { + console.log('[postinstall] react-native-document-picker already patched') + process.exit(0) +} + +content = content.replace( + 'import com.facebook.react.bridge.GuardedResultAsyncTask;', + 'import java.util.concurrent.Executors;', +) +content = content.replace( + ' new ProcessDataTask(getReactApplicationContext(), uris, copyTo, promise).execute();', + ` final ReactApplicationContext ctx = getReactApplicationContext(); + final List finalUris = uris; + final String finalCopyTo = copyTo; + Executors.newSingleThreadExecutor().execute(() -> { + WritableArray results = Arguments.createArray(); + for (Uri u : finalUris) { + results.pushMap(ProcessDataTask.getMetadataStatic(u, ctx.getApplicationContext(), finalCopyTo)); + } + promise.resolve(results); + });`, +) +content = content.replace( + 'private static class ProcessDataTask extends GuardedResultAsyncTask {', + 'private static class ProcessDataTask {', +) +content = content.replace( + ` private final WeakReference weakContext; + private final List uris; + private final String copyTo; + private final Promise promise; + + protected ProcessDataTask(ReactContext reactContext, List uris, String copyTo, Promise promise) { + super(reactContext.getExceptionHandler()); + this.weakContext = new WeakReference<>(reactContext.getApplicationContext()); + this.uris = uris; + this.copyTo = copyTo; + this.promise = promise; + } + + @Override + protected ReadableArray doInBackgroundGuarded() { + WritableArray results = Arguments.createArray(); + for (Uri uri : uris) { + results.pushMap(getMetadata(uri)); + } + return results; + } + + @Override + protected void onPostExecuteGuarded(ReadableArray readableArray) { + promise.resolve(readableArray); + } + + private WritableMap getMetadata(Uri uri) { + Context context = weakContext.get(); + if (context == null) { + return Arguments.createMap(); + }`, + ` static WritableMap getMetadataStatic(Uri uri, Context context, String copyTo) { + if (context == null) { + return Arguments.createMap(); + }`, +) +content = content.replace( + ' prepareFileUri(context, map, uri);', + ' prepareFileUri(context, map, uri, copyTo);', +) +content = content.replace( + ' private void prepareFileUri(Context context, WritableMap map, Uri uri) {', + ' private static void prepareFileUri(Context context, WritableMap map, Uri uri, String copyTo) {', +) +content = content.replace( + ' copyFileToLocalStorage(context, map, uri);', + ' copyFileToLocalStorage(context, map, uri, copyTo);', +) +content = content.replace( + ' private void copyFileToLocalStorage(Context context, WritableMap map, Uri uri) {', + ' private static void copyFileToLocalStorage(Context context, WritableMap map, Uri uri, String copyTo) {', +) +content = content.replace( + ' public File safeGetDestination(', + ' public static File safeGetDestination(', +) + +fs.writeFileSync(pickerFile, content, 'utf8') +console.log('[postinstall] react-native-document-picker patched successfully') diff --git a/src/api/demo.ts b/src/api/demo.ts index ad77937..50edd4f 100644 --- a/src/api/demo.ts +++ b/src/api/demo.ts @@ -1,6 +1,6 @@ import { load, K } from '../utils/storage' -const BASE = 'https://sentry.xuqinmin.com/api/demo' +const BASE = 'https://dev.xuqinmin.com/api/demo' const APP_ID = 'ak_demo_chat' async function getToken(): Promise { diff --git a/src/context/AuthContext.tsx b/src/context/AuthContext.tsx index 8e709cc..025be3a 100644 --- a/src/context/AuthContext.tsx +++ b/src/context/AuthContext.tsx @@ -6,7 +6,7 @@ import { save, load, clearSession, K } from '../utils/storage' import pluginMeta from '../../plugin.json' const APP_ID = 'ak_demo_chat' -const SERVER_URL = 'https://sentry.xuqinmin.com' +const SERVER_URL = 'https://dev.xuqinmin.com' interface AuthState { ready: boolean