AutoJs6 icon indicating copy to clipboard operation
AutoJs6 copied to clipboard

打包APK签名问题

Open chanwu1100 opened this issue 2 months ago • 2 comments

作者您好,我在使用项目中遇到了如下问题,希望解惑一下: 我想获取设备唯一标识,IMEI无法获取,只能使用device.getAndroidId()。 但是在脚本中使用获得的,与打包APK之后获得的,不是一个。 百度搜了下发现是因为两个软件签名不一致,所以安卓系统返回的id也就不一样了,请问如何解决? 目前想法是打包的APK使用的签名与autojs6的APK的签名保持一致,就可以保持androidId不变,但是不知道如何实现,不确定是否需要修改源码。

chanwu1100 avatar Oct 14 '25 12:10 chanwu1100

您好, 感谢反馈.

@SuppressLint("HardwareIds")
public String getAndroidId() {
    return Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.ANDROID_ID);
}

不考虑多用户的情况下, 上述代码在同一个设备 (Android 8.0+) 不同签名的应用中, 获取到的值是不一致的. 可以发现, 读取 ANDROID_ID 并不需要额外的权限, 但它不适合作为跨应用跨设备的 "设备唯一标识", 否则它很容易作为重要的隐私信息之一被任意应用获取.

另外, 签名一致手段虽然理论上可行, 但 AutoJs6 的签名私钥是不可公开的 (它相当于身份证这样的身份证明, 公开后任何开发者都能够以我的名义发布 AutoJs6 应用).

我们可以换一个角度, 不依赖 ANDROID_ID. 因为你的使用范围以 "设备" 为单位, 只要保证同一设备中, AutoJs6 与其所有打包应用可以共享同一个唯一标识, 就可以实现目标.

如果优先考虑不打扰用户去选则目录或文件 (即不需要用户交互), 可以把新生成的一个 UUID 作为 "共享设备 ID" 放在 AutoJs6 内, 并通过一个 ContentProvider 对外只读暴露. 思路如下:

  • 共享设备 ID 的唯一来源在 AutoJs6 本体应用内: 首次生成 UUID 并持久化 (可能会考虑私有文件方式)
  • 通过一个只读 ContentProvider 对外暴露读取接口; 任意应用均可读, 但不可写
  • 封装方法挂载到全局模块 (如 device 模块), 内部实现主要通过 ContentResolver.query 静默获取共享设备 ID

未来 AutoJs6 会考虑支持一个 device.getSharedDeviceId() 方法, 使用方法如下:

const sharedDeviceId = device.getSharedDeviceId();
toastlog(sharedDeviceId);

功能实现之后, 所有 AutoJs6 的打包应用与 AutoJs6 本体应用运行上述代码, 都会获取到相同的结果.

内部关键代码:

<manifest ... >
    <application ... >
        <provider
            android:name="org.autojs.autojs.deviceid.DeviceIdProvider"
            android:authorities="${applicationId}.deviceid.provider"
            android:exported="true" />
    </application>
</manifest>
class DeviceIdProvider : ContentProvider() {

    companion object {
        private const val AUTH = "org.autojs.autojs6.deviceid.provider"
        private const val PATH = "v1/device_id"
        private const val CODE = 1
        private const val COL = "device_id"
        private const val SP_NAME = "device_id_prefs"
        private const val SP_KEY = "device_id"
        private val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
            addURI(AUTH, PATH, CODE)
        }
    }

    override fun onCreate(): Boolean {
        ensureId()
        return true
    }

    private fun ensureId(): String {
        val sp = context!!.getSharedPreferences(SP_NAME, 0)
        val exist = sp.getString(SP_KEY, null)
        if (exist != null) return exist
        val id = UUID.randomUUID().toString()
        sp.edit { putString(SP_KEY, id) }
        return id
    }

    override fun query(
        uri: Uri, projection: Array<out String>?, selection: String?,
        selectionArgs: Array<out String>?, sortOrder: String?,
    ): Cursor? {
        if (matcher.match(uri) != CODE) return null
        val id = ensureId()
        val cursor = MatrixCursor(arrayOf(COL), 1)
        cursor.addRow(arrayOf(id))
        return cursor
    }

    override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
        if (method == "getDeviceId") {
            val id = ensureId()
            return Bundle().apply { putString(COL, id) }
        }
        return super.call(method, arg, extras)
    }

    override fun getType(uri: Uri) = "vnd.android.cursor.item/$AUTH.$PATH"
    override fun insert(uri: Uri, values: ContentValues?) = null
    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) = 0
    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?) = 0

}
fun getSharedDeviceId(scriptRuntime: ScriptRuntime, args: Array<out Any?>): String? = ensureArgumentsIsEmpty(args) {
    val uri = "content://org.autojs.autojs6.deviceid.provider/v1/device_id".toUri()
    globalContext.contentResolver.query(uri, arrayOf("device_id"), null, null, null)?.use { c ->
        if (c.moveToFirst()) c.getString(0) else null
    }
}

注: 示例代码没有使用私有文件方式, 而是 SharedPreferences 方式. 另外, 未来同时会考虑在 AutoJs6 应用设置中, 针对共享设备 ID 提供 [ 修改/重置/关闭共享 ] 等相关设置选项.

如有其他疑问, 欢迎继续反馈.

SuperMonster003 avatar Oct 30 '25 03:10 SuperMonster003

感谢作者耐心的回答,足够解惑了~ 并感谢给出的解决方案~ 学习学习

chanwu1100 avatar Nov 13 '25 08:11 chanwu1100