Android Studio 1.5.1 配置编译NDK参考文档

Android Studio 1.5.1上面对于NDK的编译进一步简化,只需要在工程的defaultConfig设置中增加如下配置就可以了:

ndk {
    moduleName "jni_module"
    ldLibs "log"
    abiFilters "armeabi"
}

新建的工程中的app目录下的build.gradle中的内容如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.my.myapplication"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

修改后的配置文件如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.my.myapplication"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        
        ndk {
            moduleName "jni_module"
            ldLibs "log"
            abiFilters "armeabi"
        }
        
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

然后在app->src->main目录下创建jni目录就可以了。

如果此时提示:

Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

则在修改工程目录下的gradle.properties,在文件中新建一行,添加如下:

android.useDeprecatedNdk=true

注意,还需要在local.properties设置NDK的路径

ndk.dir=D\:\\Android\\android-ndk-r10e

默认情况下,build.gradle中的代码是不能进行调试的,需要增加两个配置项:

jniDebuggable true
debuggable true

修改后的配置文件如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.my.myapplication"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        
        ndk {
            moduleName "jni_module"
            ldLibs "log"
            abiFilters "armeabi"
        }
        
    }
    buildTypes {
        debug{
            jniDebuggable true
            debuggable true
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

一般在debug项中增加提示即可,如果想在release中也支持Debug的话,上面两句话在release中增加即可。修改后的结果如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.my.myapplication"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        
        ndk {
            moduleName "jni_module"
            ldLibs "log"
            abiFilters "armeabi"
        }
        
    }
    buildTypes {
        debug{
            jniDebuggable true
            debuggable true
        }
        release {
            jniDebuggable true
            debuggable true
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

Android Studio中使用SystemProperties

概述


Android的系统属性相当于Windows的注册表,由key和value组成,且都是核心系统的一个基本机制。相对于Windows的注册表,Android的系统属性要简单一些,它没有Windows注册表的树状结构,而只是一个列表,也就是说没有父子关系。value有string,int,long,boolean,但是设置只能通过字符串方式。

读取系统属性,是通过SystemProperties类来实现的。SystemProperties在android.os下,但这个类是隐藏的,上层程序开发无法直接使用。要使用这个类,有两种方法。一个是导入layoutlib.jar,另外一种是通过反射的方式调用。

导入layoutlib.jar


我们只介绍一下如何在Android Studio中导入的方式
在gradle配置文件中,写一个函数,动态获取layoutlib.jar路径,然后加到dependencies中即可,代码如下:

dependencies {
    provided files(getLayoutLibPath())
}

/** ZhangChao time:2014-12-31,get layoutlib.jar path. android.os.SystemProperties need it. */
// must called after "android" definition
def getLayoutLibPath() {
    def rootDir = project.rootDir
    def localProperties = new File(rootDir, "local.properties")
    if (localProperties.exists()) {
        Properties properties = new Properties()
        localProperties.withInputStream {
            instr -> properties.load(instr)
        }
        def sdkDir = properties.getProperty('sdk.dir')
        def compileSdkVersion = android.compileSdkVersion
        Console.println("app compileSdkVersion : " + compileSdkVersion)
        def androidJarPath = sdkDir + "/platforms/" + compileSdkVersion + "/data/layoutlib.jar"
        return androidJarPath
    }
    return rootDir
}

导入之后,直接

import android.os.SystemProperties;

就可以正常使用了。
注意:引入的layoutlib.jar并不会编译到APK包里面,因此不需要担心增加最终的APK的大小的情况。

反射调用


对于不想引入layoutlib.jar的情况,可以直接使用下面的反射类来实现调用。

import java.lang.reflect.Method;

public class PropertyUtils {

    private static volatile Method set = null;
    private static volatile Method get = null;

    public static void set(String prop, String value) {

        try {
            if (null == set) {
                synchronized (PropertyUtils.class) {
                    if (null == set) {
                        Class<?> cls = Class.forName("android.os.SystemProperties");
                        set = cls.getDeclaredMethod("set", new Class<?>[]{String.class, String.class});
                    }
                }
            }
            set.invoke(null, new Object[]{prop, value});
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }


    public static String get(String prop, String defaultvalue) {
        String value = defaultvalue;
        try {
            if (null == get) {
                synchronized (PropertyUtils.class) {
                    if (null == get) {
                        Class<?> cls = Class.forName("android.os.SystemProperties");
                        get = cls.getDeclaredMethod("get", new Class<?>[]{String.class, String.class});
                    }
                }
            }
            value = (String) (get.invoke(null, new Object[]{prop, defaultvalue}));
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return value;
    }
}

参考链接


Android Studio 中如何引入 layoutlib.jar?

gradlew常用命令

  • ./gradlew -v 版本号
  • ./gradlew clean 清除工程目录下的build文件夹
  • ./gradlew build 检查依赖并编译打包

这里注意的是 ./gradlew build 命令把debug、release环境的包都打出来,如果正式发布只需要打Release的包,该怎么办呢,下面介绍一个很有用的命令 assemble, 如

  • ./gradlew assembleDebug 编译并打Debug包
  • ./gradlew assembleRelease 编译并打Release的包

除此之外,assemble还可以和productFlavors结合使用,比如定义了 installRelease ,uninstallRelease 两个productFlavors,则可以如下命令:

  • ./gradlew installRelease Release模式打包并安装
  • ./gradlew uninstallRelease 卸载Release模式包

gradle编译脚本需要重新下载gradle问题

使用gradlew来build项目时,总是需要下载gradle-2.8-all.zip。但是gradle-2.8-all.zip非常大,有60MB左右,而服务器又在国外,因此经常各种下载失败。

从本地安装的方法如下:

  1. 先下载gradle-2.8-all.zip包。
  2. 把下载好的zip包放到{project.dir}\gradle\wrapper目录下(也就是跟gradle-wrapper.properties 同一个目录)修改{project.dir}\gradle\wrapper\gradle-wrapper.properties文件。如下:
    #Wed Apr 10 15:27:10 PDT 2013
    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    #distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
    distributionUrl=gradle-2.8-all.zip
  3. 然后就运行gradlew build就行了。
  4. 安装好gradle之后把gradle-wrapper.properties改回来就行了

"gradlew build"报告错误"Could not find tools.jar"

使用Android Studio打包工程的时候,一直是成功的,但是当使用gradlew build来打包工程的时候,一直报告错误"Could not find tools.jar"。网上搜索了一下,应该是“JAVA_HOME”变量设置不正确,或者没有设置导致的,只需要设置“JAVA_HOME”指向正确的JDK目录即可。tools.jar 在JDK的lib目录下面。JRE是不存在这个JAR包的。

Android Studio 指定签名证书文件

1.先参照Android Studio中创建keystore生成指定的证书文件。

2.在app/build.gradle文件中增加signingConfigs字段:如下所示:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"
    defaultConfig {
        applicationId "com.test.example"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
	
    signingConfigs {
        debug {
            File strFile = new File("../../Keystore/Debug/debug.jks")
            storeFile file(strFile)
            storePassword "storeDebug1234567890"
            keyAlias "debugkey"
            keyPassword "aliasDebug1234567890"
            //println strFile.absolutePath;
        }
        release {
            File strFile = new File("../../Keystore/Release/release.jks")
            storeFile file(strFile)
            storePassword "storeRelease1234567890"
            keyPassword "keyRelease1234567890"
            keyAlias "releasekey"
            // println strFile.absolutePath;
        }
    }
    
    buildTypes {
        release {
            signingConfig  signingConfigs.release
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

注意

1.storeFilestorePasswordkeyAliaskeyPassword缺一不可,都必须填写,并且填写正确。

如果没有填写keyAlias,则签名时候会报告Android-APK signing error : Failed to read key from keystore

密码不正确的时候,会报告java.security.UnrecoverableKeyException: Cannot recover key
This exception may result from the fact that you had provided a key password that was different from the keystore password

2.对于Release配置,在buildTypes中必须指定

signingConfig signingConfigs.release

否则,会出现

Error: The apk for your currently selected variant(app-release-unsigned.apk) is not signed. please specify a signing configuration for this variant(release)

3.signingConfigs必须在buildTypes前面声明,否则会出现找不到配置选项的错误。

Android Studio 1.5使用junit单元测试,以及“Test running startedTest running failed: Instrumentation run failed due to 'java.lang.RuntimeException' Empty test suite”

Android Studio 1.5创建的工程,会生成两个默认的测试目录:test,androidTest,其中,test目录为在本机执行单元测试代码的目录,androidTest为在Android设备上执行单元测试代码的目录。

目录如下图所示:

android_test_directory

对于新建的工程,默认会生成相应的测试代码例子。如下图所示:

android_unit_test_example_file

请注意上图的两个文件图标的差别,一个文件的图标的右上角是两个三角标记,另一个文件的右下角是个时钟的标记。

右击androidTest目录下的ApplicationTest.java,就会出现执行测试用例的菜单。如下图:

android_unit_test_run_test_menu

但是当右击test目录下的ExampleUnitTest.java则没有任何的运行菜单。如下图:

test_menu_no_run_or_debug_menu

那么,如何执行test目录下的ExampleUnitTest.java呢?

操作方法为"View"->"Tool Windows"->"Build Variants",然后,切换Test ArtifactAndroid Instrumentation TestsUnit Tests
如下图:

Build_Variants_Menu

切换Test Artifact

Build_Variants_Window

可以看到,切换完成后,两个文件的图标互换了一下:

UnitTest_File_Icon_Switch

此时右击test目录下的ExampleUnitTest.java则会出现Run 'ExampleUnitTest',Debug 'ExampleUnitTest'的菜单了。

如下图:

ExampleUnitTest_Run_Debug_Menu

至于

Test running startedTest running failed: Instrumentation run failed due to 'java.lang.RuntimeException' 
Empty test suite

这个问题,是由于Android Studio 的BUG,导致的,一般是没有执行上述的切换命令,然后右击test目录下的ExampleUnitTest.java依旧会出现Run 'ExampleUnitTest',Debug 'ExampleUnitTest'的菜单,然后点击后,会让我们选择运行的设备,这个时候,明显是把我们当作可以在设备上运行的测试用例了,因此,找不到是必然的。

应对这个BUG的解决方法,就是清理代码,然后重新加载工程,一般可以解决这个问题了。

Android Studio编译报错“java.lang.OutOfMemoryError: GC overhead limit exceeded”

Android Studio编译报错 java.lang.OutOfMemoryError: GC overhead limit exceeded
详细的崩溃信息如下:

UNEXPECTED TOP-LEVEL ERROR:
java.lang.OutOfMemoryError: GC overhead limit exceeded
    at com.android.dx.cf.code.RopperMachine.getSources(RopperMachine.java:665)
    at com.android.dx.cf.code.RopperMachine.run(RopperMachine.java:288)
    at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:612)
    at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:412)
    at com.android.dx.cf.code.Simulator.simulate(Simulator.java:94)
    at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:782)
    at com.android.dx.cf.code.Ropper.doit(Ropper.java:737)
    at com.android.dx.cf.code.Ropper.convert(Ropper.java:346)
    at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:282)
    at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:139)
    at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:94)
    at com.android.dx.command.dexer.Main.processClass(Main.java:682)
    at com.android.dx.command.dexer.Main.processFileBytes(Main.java:634)
    at com.android.dx.command.dexer.Main.access$600(Main.java:78)
    at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:572)
    at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
    at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
    at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
    at com.android.dx.command.dexer.Main.processOne(Main.java:596)
    at com.android.dx.command.dexer.Main.processAllFiles(Main.java:498)
    at com.android.dx.command.dexer.Main.runMonoDex(Main.java:264)
    at com.android.dx.command.dexer.Main.run(Main.java:230)
    at com.android.dx.command.dexer.Main.main(Main.java:199)
    at com.android.dx.command.Main.main(Main.java:103)

解决方法:

  • 如果在整个工程中生效,则在build.gradle中增加如下配置:
    android {
    ..............
          dexOptions {
                incremental true
                javaMaxHeapSize "4g"
            }
    ...............
    }
  • 如果只在单元测试的时候生效,则在build.gradle中增加如下配置:
    android {
    ..............
        testOptions {
            android.dexOptions {
                incremental true
                javaMaxHeapSize "4g"
            }
        }
    ...............
    }

Android Studio 1.5增加Stacktrace或debug选项输出详细编译错误

Android Studio 编译工程的时候,如果出现错误,会打印如下信息:

:myapp:processDebugResources FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:processDebugResources'.
...
...

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log outp

最后会提示,增加--stacktrace,--info--debug来获取更加详细的信息。

那么如何设置这些参数呢?如下操作即可:
"Android Studio"->"preferences-Build, Execution, Deployment"->"Compiler"
如下图所示:
Android_studio_settings_debug_info_option