From 84eeecb4ccfe8a7ebb7abd0a3377c4fcbcd768a4 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Thu, 21 May 2026 15:25:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdk):=20=E6=96=B0=E5=A2=9E=20autoInitializ?= =?UTF-8?q?e()=EF=BC=8C=E6=94=BE=E5=85=A5=20license=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=8D=B3=E5=8F=AF=E5=AE=8C=E6=88=90=E5=85=A8=E9=87=8F=20SDK=20?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LicenseFile 新增 serverUrl 字段(私有化部署时由后端写入) - LicenseSDK 新增 readLicenseFileData() 供 sdk-core 反射调用 - XuqmSDK.autoInitialize(context) 从 assets/xuqm/license.xuqm 读取 appKey 和 serverUrl,一行完成公/私有化 SDK 初始化 Co-Authored-By: Claude Sonnet 4.6 --- .../src/main/java/com/xuqm/sdk/XuqmSDK.kt | 26 +++++++++++++++++++ .../java/com/xuqm/sdk/license/LicenseSDK.kt | 10 +++++++ .../com/xuqm/sdk/license/model/LicenseFile.kt | 2 ++ 3 files changed, 38 insertions(+) diff --git a/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt b/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt index 51f4c2a..01fd8ef 100644 --- a/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt +++ b/sdk-core/src/main/java/com/xuqm/sdk/XuqmSDK.kt @@ -27,6 +27,24 @@ object XuqmSDK { @Volatile private var loginSession: XuqmLoginSession? = null + /** + * Initializes the SDK automatically from the license file embedded in assets/xuqm/. + * Place the license.xuqm file downloaded from the tenant platform into your app's + * src/main/assets/xuqm/ directory — no hardcoded appKey or serverUrl needed. + * + * For private deployments the license file contains the server URL and all service + * endpoints are configured automatically. For public deployments the default endpoints + * (dev.xuqinmin.com) are used. + */ + fun autoInitialize(context: Context, logLevel: LogLevel = LogLevel.WARN) { + val (appKey, serverUrl) = readLicenseFileData(context) + ?: throw IllegalStateException( + "No license file found in assets/xuqm/. " + + "Download license.xuqm from the tenant platform and place it in src/main/assets/xuqm/." + ) + initialize(context, appKey, serverUrl, logLevel) + } + fun initialize( context: Context, appKey: String, @@ -52,6 +70,14 @@ object XuqmSDK { serverUrl?.takeIf { it.isNotBlank() }?.let { configurePrivateServer(context, appKey, it) } } + @Suppress("UNCHECKED_CAST") + private fun readLicenseFileData(context: Context): Pair? = runCatching { + val clazz = Class.forName("com.xuqm.sdk.license.LicenseSDK") + val instance = clazz.getField("INSTANCE").get(null) + val method = clazz.getMethod("readLicenseFileData", Context::class.java) + method.invoke(instance, context.applicationContext) as? Pair + }.getOrNull() + private fun configurePrivateServer(context: Context, appKey: String, serverUrl: String) { val base = serverUrl.trimEnd('/') + "/" val wsBase = serverUrl.trimEnd('/') diff --git a/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt b/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt index 1873378..2635886 100644 --- a/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt +++ b/sdk-license/src/main/java/com/xuqm/sdk/license/LicenseSDK.kt @@ -186,6 +186,16 @@ object LicenseSDK { return store.deviceId } + /** + * Returns (appKey, serverUrl) from the embedded license file, or null if no file is present. + * Called by XuqmSDK.autoInitialize() via reflection — sdk-core cannot depend on sdk-license directly. + */ + fun readLicenseFileData(context: Context): Pair? { + val licenseFile = LicenseFileReader.read(context) ?: return null + val appKey = licenseFile.appKey.takeIf { it.isNotBlank() } ?: return null + return appKey to licenseFile.serverUrl?.takeIf { it.isNotBlank() } + } + /** * Clear all license data (token, device ID, status). */ diff --git a/sdk-license/src/main/java/com/xuqm/sdk/license/model/LicenseFile.kt b/sdk-license/src/main/java/com/xuqm/sdk/license/model/LicenseFile.kt index da04d0e..c4ae8e1 100644 --- a/sdk-license/src/main/java/com/xuqm/sdk/license/model/LicenseFile.kt +++ b/sdk-license/src/main/java/com/xuqm/sdk/license/model/LicenseFile.kt @@ -11,6 +11,8 @@ data class LicenseFile( @SerializedName(value = "appName", alternate = ["app_name"]) val appName: String? = null, @SerializedName(value = "companyName", alternate = ["company_name"]) val companyName: String? = null, @SerializedName(value = "baseUrl", alternate = ["base_url"]) val baseUrl: String? = null, + // Set only for private deployments; used by XuqmSDK.autoInitialize() to configure all service endpoints. + @SerializedName(value = "serverUrl", alternate = ["server_url"]) val serverUrl: String? = null, @SerializedName(value = "issuedAt", alternate = ["issued_at"]) val issuedAt: String? = null, @SerializedName(value = "expiresAt", alternate = ["expires_at"]) val expiresAt: String? = null, )