加載外部 apk 中的資源

文章目錄

原理

apk 中的資源放在 resources.arsc、assets 中,它們都要靠 AssetManager 來訪問,我們又通過 Resources 來調用 AssetManager。
在這裏插入圖片描述

要訪問外部 apk 中的資源,就要通過該 apk 的 resources.arsc,創建一個新的 AssetManager 和一個新的 Resources。

實例

下面的例子,會在宿主 apk 中訪問外部 apk 中的一個 String 資源。

在 demo 中加入一個 String 資源,打包 simple.apk。

<string name="hello_str">hello plugin</string>

通過 AS 查看 simple.apk,看到 R.string.hello_str 的值是 0x7f0b0028
在這裏插入圖片描述
代碼:

class ResourcesActivity : AppCompatActivity() {

    companion object {
        const val PLUGIN_APK_NAME = "simple.apk"
    }

    var pluginApkPath: String = ""
    var mResources: Resources? = null

    override fun attachBaseContext(newBase: Context?) {
        super.attachBaseContext(newBase)

        // 將 simple.apk 複製到 /data/data/packageName/files
        val apkFile = newBase?.getFileStreamPath(PLUGIN_APK_NAME)
        pluginApkPath = apkFile?.absolutePath ?: ""
        FileUtil.copyFileFromAssets(newBase, PLUGIN_APK_NAME, apkFile, false)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_resources)

        // 創建新的 Resources 對象
        loadResources()
        // 7f0b0028,即 simple.apk 的 resources.arsc 中 R.string.hello_str 的 id 值
        val s = mResources?.getString("7f0b0028".toInt(16))
        tv_plugin_res_string.text = s
    }

    private fun loadResources() {
        // 創建新的 AssetManager 對象
        val mAssetManager = AssetManager::class.java.newInstance()
        // 將 simple.apk 的路徑傳入 AssetManager
        MethodUtils.invokeMethod(mAssetManager, "addAssetPath", pluginApkPath)
        // 通過 AssetManager 創建 Resources
        mResources = Resources(mAssetManager, resources.displayMetrics, resources.configuration)
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章