【问题标题】:Android instant feature: Is it something fundamentally flawed with this approach?Android 即时功能:这种方法是否存在根本缺陷?
【发布时间】:2019-04-09 03:50:00
【问题描述】:

我正在尝试在从 google gradle 插件 3.1.4 更新到现在最新的 3.2.1 后重新构建我的应用程序,我认为我首先让我的 Instantapp 工作的方法可能有问题,所以我发布这个问题是为了放弃或确认这一点,并在这种情况下要求不同的方法。

简而言之,我的应用是一个在资产文件夹中包含许多图形的游戏。为了使 Instantapp 符​​合 Google Play 规定的 10 兆字节限制,我必须删除其中一些我在即时版本中不需要的资产以及具有更高分辨率的资产,同时保留其余资产。此外,instantapp 的代码与安装的代码略有不同,所以我在那里重写了一些方法和类。

最小的 com.android.instantapp 模块似乎不能包含资产和代码,所以我创建了一个中间功能模块来代替它们。

所以,经过一番努力(主要是使用 firebase 和 com.google.gms.google-services 插件),我想出了这种方法,最终适用于 3.1.4 版的 gradle 插件(com.android .tools.build:gradle:3.1.4)

唯一奇怪的是,我必须将标志“baseFeature”设置为 android_instant_feature 和 android_common 功能模块。但它奏效了,我终于可以发布我的游戏的即时版本,而安装的版本也可以继续构建。

现在,一旦我更新到 google gradle 插件的 3.2.1 版,即使我没有更改任何其他内容,问题也会开始。在尝试构建项目时,我遇到了很多此类错误:

Unable to find a matching variant of project :android_common:
  - Variant 'debugApiElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
      - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Aar'.
      - Found org.gradle.usage 'java-api' but wasn't required.
  - Variant 'debugFeatureApiElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
      - Found com.android.build.api.attributes.VariantAttr 'debugFeature' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Feature'.
      - Found org.gradle.usage 'java-api' but wasn't required.
  - Variant 'debugFeatureRuntimeElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
      - Found com.android.build.api.attributes.VariantAttr 'debugFeature' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Feature'.
      - Found org.gradle.usage 'java-runtime' but wasn't required.
  - Variant 'debugRuntimeElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found compatible value 'debug'.
      - Found com.android.build.api.attributes.VariantAttr 'debug' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Aar'.
      - Found org.gradle.usage 'java-runtime' but wasn't required.
  - Variant 'releaseApiElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found incompatible value 'release'.
      - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Aar'.
      - Found org.gradle.usage 'java-api' but wasn't required.
  - Variant 'releaseFeatureApiElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found incompatible value 'release'.
      - Found com.android.build.api.attributes.VariantAttr 'releaseFeature' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Feature'.
      - Found org.gradle.usage 'java-api' but wasn't required.
  - Variant 'releaseFeatureRuntimeElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found incompatible value 'release'.
      - Found com.android.build.api.attributes.VariantAttr 'releaseFeature' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Feature'.
      - Found org.gradle.usage 'java-runtime' but wasn't required.
  - Variant 'releaseRuntimeElements':
      - Required com.android.build.api.attributes.BuildTypeAttr 'debug' and found incompatible value 'release'.
      - Found com.android.build.api.attributes.VariantAttr 'release' but wasn't required.
      - Required com.android.build.gradle.internal.dependency.AndroidTypeAttr 'Metadata' and found incompatible value 'Aar'.
      - Found org.gradle.usage 'java-runtime' but wasn't required.

在对 gradle 脚本进行了一些调整后,包括从 android_instant_feature 模块中删除 baseFeature true 标志,我得到了一个更简短的错误,但我不能说我是否比以前更好。错误是这样的:

预期配置 ':android_instant_feature:debugFeatureCompileClasspath' 包含 只是一个文件,但它不包含任何文件。

现在我只是被困在这里,不知道该做什么或下一步该往哪里看,所以我想知道我的方法是否存在根本性的缺陷,因为我是在反复试验后想出的'不确定它是否正常,在这种情况下,我可以使用哪种其他方法来满足我的要求和来自 Google 的要求,无论它们是什么。

根据@TWL 的要求,这些是我用于这些模块的 Gradle 文件。我已经用 com.myapp.id 替换了真正的应用程序 ID,其余的正是我所拥有的,包括很多我认为与此事无关的 libGDX 的东西,尽管我更愿意以准确性的名义把它留在那里:

android_common

apply plugin: "com.android.feature"

configurations { natives }

android {
    baseFeature true
    compileSdkVersion 28
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }

        androidTest.setRoot('tests')
    }
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        sourceSets {
            all {
                manifest.srcFile "AndroidManifest.xml"
            }
        }
        multiDexEnabled true
    }
    buildTypes {
        release {
            setMinifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    buildToolsVersion '28.0.2'
    lintOptions {
        abortOnError false
    }
    dexOptions {
        jumboMode true
    }
}

dependencies {
    application project(':android')
    implementation project(':core')
    api 'com.android.support:multidex:1.0.3'
    implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
    natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
    implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
    natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi"
    natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
    natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
    natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
    natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"
    implementation "com.android.billingclient:billing:$playBillingLibVersion"
    implementation "com.google.firebase:firebase-core:16.0.3"
    implementation "com.google.firebase:firebase-ads:15.0.1"

    implementation fileTree(include: ['*.jar'], dir: 'libs')
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.google.guava:guava:24.0-android'
}

task copyAndroidNatives() {
    file("libs/armeabi/").mkdirs();
    file("libs/armeabi-v7a/").mkdirs();
    file("libs/arm64-v8a/").mkdirs();
    file("libs/x86_64/").mkdirs();
    file("libs/x86/").mkdirs();

    configurations.natives.files.each { jar ->
        def outputDir = null
        if (jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a")
        if (jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
        if (jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi")
        if (jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64")
        if (jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
        if (outputDir != null) {
            copy {
                from zipTree(jar)
                into outputDir
                include "*.so"
            }
        }
    }
}

android_instant_feature

apply plugin: "com.android.feature"

android {
//    baseFeature true
    buildToolsVersion "28.0.2"
    compileSdkVersion 28
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ["${project(':android_common').projectDir}/res"]
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
    }
    defaultConfig {
        versionCode 4031
        versionName "4.1.2.1i"
        minSdkVersion 16
        targetSdkVersion 28
        multiDexEnabled true
    }

    dexOptions {
        jumboMode true
    }

    // Proguard configuration
    buildTypes {
        release {
            //minifyEnabled true will turn proguard ON
//            minifyEnabled true
            //proguardFiles let you add your own proguard rules ('proguard-project.txt') in this case, as its already created by gdx-setup
//            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
        }
        debug {}
    }


    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    productFlavors {
    }
    lintOptions {
        abortOnError false
    }
}

task run(type: Exec) {
    def path
    def localProperties = project.file("../local.properties")
    if (localProperties.exists()) {
        Properties properties = new Properties()
        localProperties.withInputStream { instr ->
            properties.load(instr)
        }
        def sdkDir = properties.getProperty('sdk.dir')
        if (sdkDir) {
            path = sdkDir
        } else {
            path = "$System.env.ANDROID_HOME"
        }
    } else {
        path = "$System.env.ANDROID_HOME"
    }

    def adb = path + "/platform-tools/adb"
    commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.marzoa.ruletafree/com.marzoa.ruletafree.AndroidLauncher'
}

dependencies {
    implementation project(":core")
    feature project(":android_common")
    api 'com.android.support:multidex:1.0.3'
    implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
    implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
    implementation "com.google.firebase:firebase-core:16.0.3"
    implementation 'com.google.android.gms:play-services-instantapps:16.0.0'

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

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

android_instant

apply plugin: 'com.android.instantapp'

android {
    defaultConfig {
        applicationId "com.myapp.id"
        minSdkVersion 16
        targetSdkVersion 28
        multiDexEnabled true
    }
}

dependencies {
    implementation project(":android_common")
    implementation project(":android_instant_feature")
}

安卓

apply plugin: "com.android.application"
apply plugin: 'io.fabric' // Needed by crashlytics. DO NOT REMOVE.

android {
    buildToolsVersion "28.0.2"
    compileSdkVersion 28
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ["${project(':android_common').projectDir}/res"]
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }

        androidTest.setRoot('tests')
    }
    defaultConfig {
        applicationId "com.myapp.id"
        versionCode 4032
        versionName "4.1.2.1"
        minSdkVersion 16
        targetSdkVersion 28
        multiDexEnabled true
    }
    dexOptions {
        jumboMode true
    }
    // Proguard configuration
    buildTypes {
        release {
            //minifyEnabled true will turn proguard ON
            minifyEnabled true
            //proguardFiles let you add your own proguard rules ('proguard-project.txt') in this case, as its already created by gdx-setup
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    productFlavors {
    }
    lintOptions {
        abortOnError false
    }
}

task importPuzzles(type: Exec) {
    // TODO
}

task run(type: Exec) {
    def path
    def localProperties = project.file("../local.properties")
    if (localProperties.exists()) {
        Properties properties = new Properties()
        localProperties.withInputStream { instr ->
            properties.load(instr)
        }
        def sdkDir = properties.getProperty('sdk.dir')
        if (sdkDir) {
            path = sdkDir
        } else {
            path = "$System.env.ANDROID_HOME"
        }
    } else {
        path = "$System.env.ANDROID_HOME"
    }

    def adb = path + "/platform-tools/adb"
    commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.marzoa.ruletafree/com.myapp.id.AndroidLauncher'
}

dependencies {
    implementation project(":core")
    implementation project(":android_common")
    api 'com.android.support:multidex:1.0.3'
    implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
    implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
    implementation "com.android.billingclient:billing:$playBillingLibVersion"
    implementation "com.google.firebase:firebase-core:16.0.3"
    implementation "com.google.firebase:firebase-ads:15.0.1"
    implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5'

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

// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'

提前非常感谢!

【问题讨论】:

  • 这很好奇,如果我让 com.android.instantapp 模块没有依赖项,我只能重现你的“新错误”......但当然,应该只有一个 @ 987654328@,但问题可能在于您如何配置 gradle 文件以将即时/应用程序的结构/依赖关系联系在一起,您能展示一下吗?
  • 如果instantapp 模块不包含base也可以重现
  • 非常感谢您的回答,@TWL。我的 android_instant instantapp 模块的依赖关系不是空白的,尽管它只有两个: android_common 模块和 android_instant_feature 一个。其余所需的东西已经在 android_common 或 android_instant_feature 中。这里是深夜,但我向你保证我会在明天上传略读的 gradle 文件。
  • @TWL 我已经更新了添加 Gradle 文件的问题。请注意,我已经用 com.myapp.id 替换了真实的应用程序 ID。最好的!

标签: java android firebase gradle android-instant-apps


【解决方案1】:

感谢您提供 gradle 文件,看起来您的 gradle 依赖项混淆了。

拥有baseFeature truecom.android.feature 模块应该是其依赖项同时拥有application project()feature project() 的模块。这是您的错误的主要原因:

预期配置 ':___:debugFeatureCompileClasspath' 包含 只是一个文件,但它不包含任何文件。

所以从您提供的内容来看,您的application project()feature project() 似乎是分开的。

要解决这个问题,你的“baseandroid_common 应该是:

application project(':android')
feature project(":android_instant_feature")

而您的“非基础功能android_instant_feature 应该是:

implementation project(':android_common)

这不会改变您项目的整体结构。

  • 您的com.android.application 将与以下库一起编译:coreandroid_common
  • 您的com.android.instantapp 将与免安装应用apk 一起编译:android_common.apkandroid_instant_feature.apk

现在,为什么它以前可以与 2x baseFeature 一起使用?不知道,应该没有……

以前有一个页面@https://g.co/instantapps 解释了免安装应用的结构,但您可以参考我之前的一篇文章来了解它的概述和参考链接:How can i access an activity from another feature module

旁注:我注意到您在整个模块中都有一个implementation project(":core") 通用(减去instantapp)。如果那纯粹是一个像com.android.library 这样的库,那么你不应该这样设置它。您实际上可以将它放在您的 base 中:api project(":core") 并在其他地方删除所有其他引用。将其声明为api 意味着任何也实现了基础的模块也将暴露于这种依赖关系。 (试试吧,根据您的 core 拥有的其他库,在极少数情况下会出现这种情况,但请尝试查看)。

【讨论】:

  • 感谢一百万!这是有效的。 :) 为了增加您的答案,我也必须更改 minSDKVersion,因为我有一些地方是 15,而另一些地方是 16,这显然是一个错误,与我之前的问题无关。再次,非常感谢。
猜你喜欢
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
相关资源
最近更新 更多