草庐IT

安卓java.lang.NoClassDefFoundError : R$string

coder 2023-12-18 原文

每当我运行单元测试时,当它尝试从自定义 config.xml 文件中检索字符串值时,我都会收到此错误。

背景:

该项目本身是一个库 apk 项目,它使用并引用了另一个库 APK 项目。

当项目本身尝试启动一个新对象时,会发生错误,该新对象是引用库 apk 项目中包含的父类(super class)的子类。

问题在下面有更多解释

因错误而失败的特定代码行是下面定义的静态变量:

  protected static final String ANDROID_CONFIG_ID =  LibraryApplication.getApplication().getString(R.string.api_checkout_config_id_override);

失败并出现以下错误:

java.lang.NoClassDefFoundError: com/jon/commonlib/R$string

如果您想知道的话,commonLib 就是引用的库 apk。

这是我的单元测试

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, manifest=Config.NONE)
public class TestSearchShows {

    @Test
    public void testSearchJsonFile(){
        EventsTestHelper testHelper = new EventsTestHelper(RuntimeEnvironment.application);

        try {
            ShowsList showList = testHelper.getShowList(new SearchEvent());

            if(showList.getShows().size() < 0){
                Assert.fail("show list is empty");
            }

        } catch (IOException e) {
            e.printStackTrace();
            Assert.fail(e.toString());
        }
    }


}

EventsTestHelper 是名为 NetworkHelper 的父类(super class)的子类,如下所示:

public abstract class NetworkHelper<T, P, S> implements NetworkConstants {

protected static final String ANDROID_CONFIG_ID = LibraryApplication.getApplication().getString(R.string.api_checkout_config_id_override);

//other stuff ....

}

我使用最新的 robolectric 3.0 版来运行我的单元测试。

如果我要实时运行代码并调用和启动子类,它工作得很好,没有崩溃

编辑:下面是我的构建 gradle 文件的 fragment

apply plugin: 'android-sdk-manager'
apply plugin: 'com.android.library'
apply plugin: 'crashlytics'


buildscript {
    repositories {
        jcenter()
        mavenCentral()
        maven { url 'http://download.crashlytics.com/maven' }
        maven { url 'http://www.testfairy.com/maven' }

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.1.0'
        classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.+'
        classpath 'com.crashlytics.tools.gradle:crashlytics-gradle:1.+'
        classpath 'com.testfairy.plugins.gradle:testfairy:1.+'

    }
}

repositories {
    mavenCentral()
    maven { url 'http://download.crashlytics.com/maven' }
    maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    flatDir {
        dirs 'libs'
    }
}

android {
    compileSdkVersion 19
    buildToolsVersion "22.0.1"
    def package_namespace = "com.jonney.moduleApp"

   defaultConfig {
        minSdkVersion 14
        testApplicationId "com.jonney.moduleApp"
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
 productFlavors {
        //testing {
        //}
        local {
        }
        mock {
        }
        qa {
        }
        //qa4 {
        //}
        production {
        }
    }

    sourceSets {



        local {
            res.srcDir 'build-config/local/res'
        }
        testing {
            res.srcDir 'build-config/testing/res'
        }
        mock {
            res.srcDir 'build-config/mock/res'
        }
        qa {
            res.srcDir 'build-config/qa/res'
        }
        qa4 {
            res.srcDir 'build-config/qa4/res'
        }
        staging {
            res.srcDir 'build-config/staging/res'
            test.java.srcDirs += 'src/main/java'
        }
        production {
            res.srcDir 'build-config/production/res'
            test.java.srcDirs += 'src/main/java'
            test.java.srcDirs += "build/generated/source/r/production"
            test.java.srcDirs += "build/generated/source/buildConfig/production"
        }

    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19.1.+'
    compile 'com.google.code.gson:gson:2.3'
    testCompile('org.robolectric:robolectric:3.0') {
        exclude group: 'commons-logging', module: 'commons-logging'
        exclude group: 'org.apache.httpcomponents', module: 'httpclient'
    }
    compile 'com.fasterxml.jackson:jackson-parent:2.5'
    compile 'com.squareup:otto:1.3.6'
    compile 'com.jakewharton:butterknife:6.1.0'
    compile 'com.sothree.slidinguppanel:library:3.0.0'
    compile 'com.crashlytics.android:crashlytics:1.+'
    compile 'com.mcxiaoke.volley:library-aar:1.0.0'
    compile "joda-time:joda-time:2.4"
    testCompile('junit:junit:4.12') {
        exclude module: 'hamcrest'
        exclude module: 'hamcrest-core'
    }
    testCompile 'org.hamcrest:hamcrest-all:1.3'
    compile 'com.sothree.slidinguppanel:library:3.0.0'
    compile 'com.squareup:otto:1.3.6'
    compile 'com.squareup.okhttp:okhttp:2.3.0'
    testCompile 'org.apache.maven:maven-ant-tasks:2.1.3'

    compile 'com.google.android.gms:play-services:7.0.0'

    compile 'com.android.support:multidex:1.0.0'

    compile(name: 'commonLib 1.0 1', ext: 'aar')
    testCompile(name: 'commonLib-1.0 1', ext: 'aar')
}

编辑:我还尝试手动创建一个任务,为每个依赖项复制 r 类。

    afterEvaluate { project ->
        android.libraryVariants.each { variant ->
            // workaround for missing R class for aar dependencies
            def copyTaskName = "copy${variant.name.capitalize()}AppCompat"
            def copyTaskNameTwo = "copy${variant.name.capitalize()}commonlib"
            task(copyTaskName, type:Copy) {
                dependsOn "process${variant.name.capitalize()}Resources"
                from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
                into { "build/generated/source/r/${variant.dirName}/com/jon/commonlib" }
//                into { "src/test/java/android/support/v7/appcompat" }
                include 'R.java'
                filter { line -> line.contains("package ${package_namespace};") ? 'package android.support.v7.appcompat;' : line }
                outputs.upToDateWhen { false }
            }
            task(copyTaskNameTwo, type:Copy) {
                dependsOn "process${variant.name.capitalize()}Resources"
                from { "build/generated/source/r/${variant.dirName}/$package_namespace_path" }
                into { "build/generated/source/r/${variant.dirName}/android/support/v7/appcompat" }
//                into { "src/test/java/android/support/v7/appcompat" }
                include 'R.java'
                filter { line -> line.contains("package ${package_namespace};") ? 'package com.jon.commonlib;' : line }
                outputs.upToDateWhen { false }
            }
            System.out.println("adding ${copyTaskName} build/generated/source/r/${variant.dirName}/$package_namespace_path ")
            println("basename =  ${variant.baseName}")
            println("directory name =  ${variant.dirName}")
            tasks.getByName("compile${variant.name.capitalize()}UnitTestJava") dependsOn copyTaskName
        }
    }

亲切的问候

强尼

最佳答案

The project itself is a library apk project that uses and references another library APK project.

对于此类项目,存在一个已知问题 https://github.com/robolectric/robolectric/issues/1796但您可以解决它。

基本问题是库项目的 android/gradle 行为与应用程序项目不同。它只是忽略从 aar 依赖项生成 R 类。

要解决此问题,您可以提供自己的 R 类,该类已包含所有依赖项 R 值。这里有一个 appcompat 依赖的例子

afterEvaluate { project ->
  android.libraryVariants.each { variant ->
    // one line for each aar dependency
    tasks.getByName("assemble${variant.name.capitalize()}").dependsOn copyAppcompat
  }
}

// copy it for each aar dependency and adjust it to your needs
task copyAppcompat(type: Copy) {

  // replace the base package with yours (all after /r/debug/) which contains your R.class
  from 'build/generated/source/r/debug/com/example/core'.replace("/", File.separator)

  // replace the library packages with yours (all after /test/java/) with your aar dependency base package
  into 'src/test/java/android/support/v7/appcompat'.replace("/", File.separator)

  // also replace the package declaration or you will get compile errors
  filter { line -> line.contains('package com.example.core;') ? 'package android.support.v7.appcompat;' : line }
  include 'R.java'
}

可以在 https://github.com/nenick/AndroidStudioAndRobolectric/tree/library-with-aar 找到包含您的设置的示例项目

关于安卓java.lang.NoClassDefFoundError : R$string,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32099956/

有关安卓java.lang.NoClassDefFoundError : R$string的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  6. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  7. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  8. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  9. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  10. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

随机推荐