fix: auto-init XuqmSDK via ContentProvider; remove packageName from update check; fix Jenkinsfile

- sdk-core: add XuqmInitializerProvider for auto-init at app startup
- sdk-core: register provider in AndroidManifest.xml
- sdk-license: remove duplicate XuqmSDK init from LicenseInitializerProvider
- sdk-update: awaitInitialization() now uses requireInit() directly (no 30s polling)
- Jenkinsfile: replace Windows external commands (findstr/powershell) with Groovy readFile/writeFile

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-23 04:11:23 +08:00
父节点 87ef2bf104
当前提交 db3ec3d377
共有 5 个文件被更改,包括 49 次插入29 次删除

15
Jenkinsfile vendored
查看文件

@ -50,12 +50,10 @@ pipeline {
stage('Resolve Versions') { stage('Resolve Versions') {
steps { steps {
script { script {
// Read version using cmd.exe findstr // Read version using pure Groovy (no Windows external commands)
def verRaw = bat( def props = readFile('gradle.properties')
script: '@findstr /B "PUBLISH_VERSION=" gradle.properties', def verLine = props.readLines().find { it.trim().startsWith('PUBLISH_VERSION=') }
returnStdout: true def currentVer = verLine ? verLine.split('=', 2)[1].trim() : '0.1.0'
).trim()
def currentVer = verRaw.contains('=') ? verRaw.split('=', 2)[1].trim() : '0.1.0'
echo "Current PUBLISH_VERSION: ${currentVer}" echo "Current PUBLISH_VERSION: ${currentVer}"
def parts = currentVer.tokenize('.') def parts = currentVer.tokenize('.')
@ -72,8 +70,9 @@ pipeline {
echo "Auto-bumped PUBLISH_VERSION: ${currentVer} → ${newVer}" echo "Auto-bumped PUBLISH_VERSION: ${currentVer} → ${newVer}"
env.NEW_VERSION = newVer env.NEW_VERSION = newVer
// Write back using powershell // Write back using pure Groovy
bat "powershell -Command \"(Get-Content gradle.properties) -replace '^PUBLISH_VERSION=.*', 'PUBLISH_VERSION=${newVer}' | Set-Content -NoNewline gradle.properties\"" def newProps = props.replaceAll(/(?m)^PUBLISH_VERSION=.*/, "PUBLISH_VERSION=${newVer}")
writeFile(file: 'gradle.properties', text: newProps)
def modules = env.PUBLISH_MODULES.split(',').toList() def modules = env.PUBLISH_MODULES.split(',').toList()
def versionMap = [:] def versionMap = [:]

查看文件

@ -0,0 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<provider
android:name="com.xuqm.sdk.internal.XuqmInitializerProvider"
android:authorities="${applicationId}.xuqm-init"
android:exported="false"
android:initOrder="90" />
</application>
</manifest>

查看文件

@ -0,0 +1,30 @@
package com.xuqm.sdk.internal
import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import com.xuqm.sdk.XuqmSDK
/**
* Auto-initializes XuqmSDK at app startup when a license file is present.
* Registered in sdk-core AndroidManifest so any module (im/update/push/license)
* triggers one-shot initialization without explicit init calls from the app.
*/
class XuqmInitializerProvider : ContentProvider() {
override fun onCreate(): Boolean {
val ctx = context?.applicationContext ?: return true
runCatching {
if (!XuqmSDK.isInitialized()) {
XuqmSDK.autoInitialize(ctx)
}
}
return true
}
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? = null
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int = 0
}

查看文件

@ -10,14 +10,8 @@ class LicenseInitializerProvider : ContentProvider() {
override fun onCreate(): Boolean { override fun onCreate(): Boolean {
val ctx = context ?: return true val ctx = context ?: return true
LicenseContextHolder.init(ctx) LicenseContextHolder.init(ctx)
// Auto-initialize the full SDK if a license file is present in assets/xuqm/. // SDK initialization is handled by sdk-core XuqmInitializerProvider.
// Runs before Application.onCreate(), so no app-level init code is needed. // This provider only ensures LicenseContextHolder has the application context.
runCatching {
val licenseFile = LicenseFileReader.read(ctx) ?: return@runCatching
val appKey = licenseFile.appKey.takeIf { it.isNotBlank() } ?: return@runCatching
val serverUrl = licenseFile.serverUrl?.takeIf { it.isNotBlank() }
XuqmSDK.initialize(ctx, appKey, serverUrl)
}
return true return true
} }

查看文件

@ -49,19 +49,7 @@ object UpdateSDK {
}.getOrNull() }.getOrNull()
} }
private suspend fun awaitInitialization() { private fun awaitInitialization() {
val xuqmClazz = runCatching { Class.forName("com.xuqm.sdk.XuqmSDK") }.getOrNull()
if (xuqmClazz != null) {
val isInitMethod = xuqmClazz.getMethod("isInitialized")
val maxWaitMs = 30000L
val start = System.currentTimeMillis()
while (!(isInitMethod.invoke(null) as Boolean)) {
if (System.currentTimeMillis() - start > maxWaitMs) {
throw IllegalStateException("UpdateSDK initialization timed out waiting for XuqmSDK")
}
kotlinx.coroutines.delay(100)
}
}
XuqmSDK.requireInit() XuqmSDK.requireInit()
} }