From 173c3cbddddd826a43b2b1a3a88a27144a7b2c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E5=8B=A4=E6=B0=91?= Date: Mon, 27 Apr 2026 17:18:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdk):=20=E5=88=9D=E5=A7=8B=E5=8C=96=20Andr?= =?UTF-8?q?oid=20SDK=20=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 SDK 配置管理、网络请求客户端和令牌存储功能 - 实现即时通讯 IM 模块,包括消息收发、群组管理和会话功能 - 集成推送服务和应用更新功能模块 - 创建示例应用演示 SDK 使用方法 - 配置项目依赖管理和构建设置 --- android/app/build.gradle | 7 +++ android/build.gradle | 1 + android/gradle.properties | 3 ++ docs/README.md | 6 +-- scripts/postinstall.js | 105 ++++++++++++++++++++++++++++++++++++ src/api/demo.ts | 2 +- src/context/AuthContext.tsx | 2 +- 7 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 scripts/postinstall.js 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