0

我正在关注谷歌示例以在我的应用程序中使用动态交付功能。我的示例应用程序在 pie 上运行良好,但在 marshmallow 6.0.1 自定义 rom 上崩溃,因为我的选项卡在 kitkat 4.4.4 之后不支持官方更新。我在内部测试中上传了应用程序(.abb),从我的手机(os pie)和我的标签(os marshmallow)上的Play商店下载,我在两者上运行应用程序,下载动态模块,成功下载后,我启动模块,模块在 Pie 上启动,但在 Marshmallow 上崩溃,找不到资源异常。经过一些研究,stackoverflow中有人说我只是更新版本代码并重新上传应用程序,它工作正常,所以我尝试修改版本代码并测试它在棉花糖上工作正常。

有人可以帮我看看我在这里缺少什么吗?

清单(动态模块)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
xmlns:tools="http://schemas.android.com/tools"
package="com.testdynamicdelivery.ondemand.kotlin_test">

<dist:module
    dist:instant="false"
    dist:title="@string/title_kotlin_test">
    <dist:delivery>
        <dist:on-demand />
    </dist:delivery>

    <dist:fusing dist:include="true" />
</dist:module>

<application
    tools:ignore="GoogleAppIndexingWarning">
    <activity android:name="com.testdynamicdelivery.ondemand.TestKotlin">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
        </intent-filter>
    </activity>
</application>

</manifest>

构建 Gradle 文件(Dunamic 模块)

apply plugin: 'com.android.dynamic-feature'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 29

defaultConfig {
    minSdkVersion 19
    targetSdkVersion 29
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':app')
}

TestKotlin 活动(动态模块)

class TestKotlin : AppCompatActivity() {

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this)
}

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

应用程序文件(基础应用程序)

class MyApplication : SplitCompatApplication() {

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    SplitCompat.install(this)
}
}

BaseSplitActivity(基础应用程序)

abstract class BaseSplitActivity : AppCompatActivity() {

override fun attachBaseContext(newBase: Context) {
    super.attachBaseContext(newBase)
    SplitCompat.install(this)
}
}

主要活动(基础应用程序)

private const val CONFIRMATION_REQUEST_CODE = 1
private const val PACKAGE_NAME = "com.testdynamicdelivery"
private const val PACKAGE_NAME_ONDEMAND = "$PACKAGE_NAME.ondemand"
private const val KOTLIN_SAMPLE_CLASSNAME = "$PACKAGE_NAME_ONDEMAND.TestKotlin"

class MainActivity : AppCompatActivity() {

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase)
    SplitCompat.install(this)
}

/** Listener used to handle changes in state for install requests. */
private val listener = SplitInstallStateUpdatedListener { splitInstallSessionState ->

    when (splitInstallSessionState.status()) {

        SplitInstallSessionStatus.PENDING ->{
            sb.append("\nPending Feature")
            setText()
        }

        SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION ->{
            /*
            This may occur when attempting to download a sufficiently large module.
            In order to see this, the application has to be uploaded to the Play Store.
            Then features can be requested until the confirmation path is triggered.
            */
            manager.startConfirmationDialogForResult(splitInstallSessionState, this, CONFIRMATION_REQUEST_CODE)
        }

        SplitInstallSessionStatus.DOWNLOADED ->{
            sb.append("\nFeature Downloaded.")
            setText()
        }

        SplitInstallSessionStatus.CANCELING ->{
            sb.append("\nCanceling Feature.")
            setText()
        }

        SplitInstallSessionStatus.INSTALLED -> {
            sb.append("\nFeature Installed.")
            setText()
        }

        SplitInstallSessionStatus.CANCELED ->
        {
            sb.append("\nCanceled Feature.")
            setText()
        }

        SplitInstallSessionStatus.DOWNLOADING ->
        {
            sb.append("\nDownloading Feature...")
            progressBar.max = splitInstallSessionState.totalBytesToDownload().toInt()
            progressBar.progress = splitInstallSessionState.bytesDownloaded().toInt()
            setText()
        }

        SplitInstallSessionStatus.INSTALLING ->
        {
            sb.append("\nInstalling Feature...")
            setText()
        }

        SplitInstallSessionStatus.UNKNOWN ->
        {
            sb.append("\nError: ${splitInstallSessionState.errorCode()} for module ${splitInstallSessionState.moduleNames()}")
            setText()
        }

        SplitInstallSessionStatus.FAILED ->
        {
            sb.append("\nFailed ${splitInstallSessionState.errorCode()} , ${splitInstallSessionState.moduleNames()}")
            setText()
        }
    }
    /*if (splitInstallSessionState.sessionId() == mySessionID) {


    }*/
}

/** This is needed to handle the result of the manager.startConfirmationDialogForResult
request that can be made from SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION
in the listener above. */
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == CONFIRMATION_REQUEST_CODE) {
        // Handle the user's decision. For example, if the user selects "Cancel",
        // you may want to disable certain functionality that depends on the module.
        if (resultCode == Activity.RESULT_CANCELED) {
            Toast.makeText(context, "You Canceled To Download!", Toast.LENGTH_LONG).show()
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data)
    }
}

private lateinit var context: Context
private lateinit var manager: SplitInstallManager
private lateinit var progressBar: ProgressBar
private var mySessionID: Int = 0
private val sb = StringBuilder()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    context = this
    manager = SplitInstallManagerFactory.create(this)
    progressBar = findViewById(R.id.progress_bar)
    sb.append("Logs: Version: ${BuildConfig.VERSION_NAME}, Code: ${BuildConfig.VERSION_CODE}")
    setText()
    setClickListeners()
}

private fun displayProgress() {
    progressBar.visibility = View.VISIBLE
}

private fun setClickListeners()
{
    btn_feature_kotlin.setOnClickListener {
        if (manager.installedModules.contains("kotlin_test"))
        {
            sb.append("\nStarting $KOTLIN_SAMPLE_CLASSNAME")
            setText()
            launchActivity(KOTLIN_SAMPLE_CLASSNAME)
        }
        else
        {
            sb.append("\nDownloading Feature Kotlin")
            setText()
            downloadDynamicModule("kotlin_test")
        }
    }
}

override fun onResume() {
    // Listener can be registered even without directly triggering a download.
    manager.registerListener(listener)
    super.onResume()
}

override fun onPause() {
    // Make sure to dispose of the listener once it's no longer needed.
    manager.unregisterListener(listener)
    super.onPause()
}

private fun downloadDynamicModule(module: String) {

    displayProgress()

    val request = SplitInstallRequest
        .newBuilder()
        .addModule(module)
        .build()

    manager.registerListener(listener)

    manager.startInstall(request)
        .addOnFailureListener {
            sb.append("\nException: ${it.message}")
            setText()
            println("Exception: $it")
        }
        .addOnSuccessListener { sessionId ->
            sb.append("\nSuccess getting session id: $sessionId")
            setText()
            mySessionID = sessionId
        }
        .addOnCompleteListener {
            sb.append("\naddOnCompleteListener")
            setText()
        }
}

private fun setText()
{
    tv_logs.text = sb.toString()
    scroll_view.post { scroll_view.fullScroll(ScrollView.FOCUS_DOWN) }
}

/** Launch an activity by its class name. */
private fun launchActivity(className: String) {
    val intent = Intent().setClassName(BuildConfig.APPLICATION_ID, className)
    startActivity(intent)
}
}

构建 Gradle 文件(基础应用程序)

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
    applicationId 'com.testdynamicdelivery.ondemand'
    minSdkVersion 19
    targetSdkVersion 29
    versionCode 28
    versionName '1.2.8'
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}


dynamicFeatures = [":features:kotlin_test"]
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

// Play Core
api 'com.google.android.play:core:1.6.4'
// Support Library
//implementation 'com.android.support:appcompat-v7:28.0.0'

// Android X Libraries
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.core:core-ktx:1.1.0'
api 'androidx.legacy:legacy-support-v4:1.0.0'
api "androidx.lifecycle:lifecycle-extensions:2.1.0"
api 'androidx.constraintlayout:constraintlayout:1.1.3'
api 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
api 'androidx.gridlayout:gridlayout:1.0.0'
api 'androidx.cardview:cardview:1.0.0'
api 'androidx.recyclerview:recyclerview:1.1.0'
}
4

2 回答 2

2

一些从 Cyanogen 6 和 6.0.1 派生的自定义 ROM 在从拆分 APK 加载资源时存在问题,这是一个已知问题。

除了不启用按屏幕密度和语言进行拆分外,您无能为力。

您能否向 Google 提交您发现有问题的设备列表中的错误?

于 2019-12-03T07:10:01.357 回答
1

在清单中写入条件以在 sdk<=23 的安装时下载动态模块

<dist:module
    dist:instant="false"
    dist:title="@string/chat">
    <dist:delivery>
        <dist:on-demand />
        <dist:install-time>
            <dist:conditions>
                <dist:min-sdk dist:value="21" />
                <dist:max-sdk dist:value="23" />
            </dist:conditions>
        </dist:install-time>
    </dist:delivery>
    <dist:fusing dist:include="true" />
</dist:module>
于 2020-09-08T05:14:20.497 回答