Android Studio 3.2.1在build.gradle中输出自定义日志&查看构建日志

在使用Android Studio开发Android项目的时候,我们有时候需要在build.gradle中增加一部分日志,来分析编译执行情况。

早期版本只能使用logger对象输出内容,如下:

logger.quiet('An info log message which is always logged.')
logger.error('An error log message.')
logger.warn('A warning log message.')
logger.lifecycle('A lifecycle info log message.')
logger.info('An info log message.')
logger.debug('A debug log message.')
logger.trace('A trace log message.')

目前最新的gradle 4.6版本已经支持println函数输出日志,如下:

println 'A message which is logged at QUIET level'

只是,目前的Android Studio 3.2.1版本中,默认情况下,输出信息被简化了,导致我们找不到添加的输出内容。

只需要点击Build选项卡中的Toggle view选项,就可以看到我们的输出了。

具体操作如下图:
继续阅读Android Studio 3.2.1在build.gradle中输出自定义日志&查看构建日志

解决Android Studio 3.2.1版本在编译Vulkan时报告错误"Could not find com.android.tools.build:aapt2:3.2.1-4818971"

目前的最新Android Studio 3.2.1版本在编译Vulkan时报告错误"Could not find com.android.tools.build:aapt2:3.2.1-4818971",详细错误信息如下:

org.gradle.api.UncheckedIOException: Failed to capture snapshot of input files for task ':examples/:radialblur:mergeDebugResources' property 'aapt2FromMaven' during up-to-date check.
	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.snapshotTaskFiles(CacheBackedTaskHistoryRepository.java:331)
	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.createExecution(CacheBackedTaskHistoryRepository.java:151)
	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.access$100(CacheBackedTaskHistoryRepository.java:61)
	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository$1.getCurrentExecution(CacheBackedTaskHistoryRepository.java:111)
	at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.getStates(DefaultTaskArtifactStateRepository.java:208)
	at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.isUpToDate(DefaultTaskArtifactStateRepository.java:93)
	at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:50)
	at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
	at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
	at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:59)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:256)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:249)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:238)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:663)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:597)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':examples/:radialblur:_internal_aapt2_binary'.
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:944)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$1600(DefaultConfiguration.java:120)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getFiles(DefaultConfiguration.java:918)
	at org.gradle.api.internal.file.AbstractFileCollection.iterator(AbstractFileCollection.java:68)
	at org.gradle.api.internal.changedetection.state.AbstractFileCollectionSnapshotter$FileCollectionVisitorImpl.visitCollection(AbstractFileCollectionSnapshotter.java:72)
	at org.gradle.api.internal.file.AbstractFileCollection.visitRootElements(AbstractFileCollection.java:234)
	at org.gradle.api.internal.file.CompositeFileCollection.visitRootElements(CompositeFileCollection.java:185)
	at org.gradle.api.internal.changedetection.state.AbstractFileCollectionSnapshotter.snapshot(AbstractFileCollectionSnapshotter.java:55)
	at org.gradle.api.internal.changedetection.state.DefaultGenericFileCollectionSnapshotter.snapshot(DefaultGenericFileCollectionSnapshotter.java:38)
	at org.gradle.api.internal.changedetection.state.CacheBackedTaskHistoryRepository.snapshotTaskFiles(CacheBackedTaskHistoryRepository.java:329)
	... 36 more
Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find com.android.tools.build:aapt2:3.2.1-4818971.
Searched in the following locations:
    file:/Users/user/Library/Android/sdk/extras/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971.pom
    file:/Users/user/Library/Android/sdk/extras/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971-osx.jar
    file:/Users/user/Library/Android/sdk/extras/google/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971.pom
    file:/Users/user/Library/Android/sdk/extras/google/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971-osx.jar
    file:/Users/user/Library/Android/sdk/extras/android/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971.pom
    file:/Users/user/Library/Android/sdk/extras/android/m2repository/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971-osx.jar
    https://jcenter.bintray.com/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971.pom
    https://jcenter.bintray.com/com/android/tools/build/aapt2/3.2.1-4818971/aapt2-3.2.1-4818971-osx.jar
Required by:
    project :examples/:radialblur
	at org.gradle.internal.resolve.result.DefaultBuildableComponentResolveResult.notFound(DefaultBuildableComponentResolveResult.java:38)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolveModule(RepositoryChainComponentMetaDataResolver.java:108)
	at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolve(RepositoryChainComponentMetaDataResolver.java:63)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.ComponentResolversChain$ComponentMetaDataResolverChain.resolve(ComponentResolversChain.java:93)
	at org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver.resolve(ClientModuleResolver.java:60)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.resolve(ComponentState.java:163)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.getMetaData(ComponentState.java:174)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.EdgeState.calculateTargetConfigurations(EdgeState.java:137)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.EdgeState.attachToTargetConfigurations(EdgeState.java:108)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.attachToTargetRevisionsSerially(DependencyGraphBuilder.java:236)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolveEdges(DependencyGraphBuilder.java:226)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.traverseGraph(DependencyGraphBuilder.java:140)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolve(DependencyGraphBuilder.java:111)
	at org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultArtifactDependencyResolver.resolve(DefaultArtifactDependencyResolver.java:92)
	at org.gradle.api.internal.artifacts.ivyservice.DefaultConfigurationResolver.resolveGraph(DefaultConfigurationResolver.java:146)
	at org.gradle.api.internal.artifacts.ivyservice.ShortCircuitEmptyConfigurationResolver.resolveGraph(ShortCircuitEmptyConfigurationResolver.java:73)
	at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.resolveGraph(ErrorHandlingConfigurationResolver.java:66)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$4.run(DefaultConfiguration.java:494)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveGraphIfRequired(DefaultConfiguration.java:485)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveToStateOrLater(DefaultConfiguration.java:470)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$1700(DefaultConfiguration.java:120)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getSelectedArtifacts(DefaultConfiguration.java:927)
	at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getFiles(DefaultConfiguration.java:915)
	... 43 more

导致问题的原因为源代码根目录下的build.gradle中缺少对于google源服务器的配置(话说,貌似以前版本的都在jcenter中可以找到,最新版本的,好像没有上传到jcenter服务器了,估计是google的商业策略了,在此不多做评述)

打开该文件里面的内容显示如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

解决方法为在allprojects字段中增加google()源服务器。

修改后的配置变更如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

参考链接


Build errors after Android Studio 3.2.1 upgrade

Android Studio 2.3调试小米手机安装失败

Android Studio 2.3调试小米手机MIUI 8.7.4的时候,安装APK一直失败,错误信息如下:

$ adb install-multiple -r /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_7.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_6.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_8.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_9.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_3.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_4.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/dep/dependencies.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_2.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_5.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_0.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_1.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/outputs/apk/app-debug.apk 
$ adb shell pm uninstall com.guo.duoduo.anyshareofandroid
$ adb install-multiple -r /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_7.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_6.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_8.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_9.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_3.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_4.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/dep/dependencies.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_2.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_5.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_0.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/intermediates/split-apk/debug/slices/slice_1.apk /Users/longsky/Source/AnyShareOfAndroid/app/build/outputs/apk/app-debug.apk 
$ adb shell pm uninstall com.guo.duoduo.anyshareofandroid
DELETE_FAILED_INTERNAL_ERROR
Error while Installing APKs

网上查询了一下,是MIUI自身的优化导致的问题。
解决方法就是在MIUI->设置->更多设置->开发者选项->启用MIUI优化,关闭这个选项就可以了。

参考链接


Android Studio 2.3 adb install-multiple Failed to create session Failure [UNS...

macOS Sierra (10.12.4)下使用Android Studio打开Android Virtual Device Manager报告“/dev/kvm is not found”错误

Android Virtual Device Manager突然出现了/dev/kvm is not found这个错误,我猜测大概Hardware_Accelerated_Execution_Manager丢失了某些文件,或者没安装好HAXM

继续阅读macOS Sierra (10.12.4)下使用Android Studio打开Android Virtual Device Manager报告“/dev/kvm is not found”错误

Android Studio 2.2 启用代码混淆

在新版本的Android Studio中开启混淆的方法如下:

buildTypes {
        release {
            minifyEnabled true //是否混淆
            shrinkResources true //是否去除无效的资源文件
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

具体解释一下minifyEnabled用来影响是不是开启混淆,shrinkResources只有在minifyEnabledtrue的情况下,才能有效,用来去除无效的资源文件。proguard-android-optimize.txtAndroid SDK->tools\proguard目录下,Google已经写好默认的混淆模板文件,其中的proguard-android.txt默认没有配置代码优化,而proguard-android-optimize.txt默认配置了代码优化,至于我们自己工程下面的proguard-rules.pro文件,只要配置我们自定义的额外配置即可,其他的用默认配置即可。

顺便讲一下代码混淆的好处:

1.代码安全,不易理解,增加破解难度。

2.减小APK的体积,减少内存开销。

3.缩减类名,方法名的长度,减少CPU开销。

参考链接


Android Studio 混淆代码时提示 “Warning:org.apache.commons.httpclient.util.URIUtil: can't find referenced class org.apache.commons.codec.net.URLCodec”

Android混淆代码时提示"Warning:org.apache.commons.httpclient.util.URIUtil: can't find referenced class org.apache.commons.codec.net.URLCodec"
解决方法是proguard-rules.pro中增加如下语句:

-dontwarn org.apache.commons.httpclient.**

其他类似的警告信息,可以参考以上的方法,逐行添加即可。

参考链接


ProGuard error can't find superclass or interface org.apache.http.entity

Android Studio升级到2.2正式版本后,在Windows命令行中执行“gradlew build”时,报告错误“Unsupported major.minor version 52.0”

Android Studio升级到2.2正式版本后,在Android Studio中编译一切正常。但是在Windows命令行中执行“gradlew build”时,报告如下错误:

* What went wrong:
A problem occurred evaluating project ':XXX'.
> java.lang.UnsupportedClassVersionError: com/android/build/gradle/LibraryPlugin
 : Unsupported major.minor version 52.0

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

这个原因,目前本人遇到的原因是,机器上同时安装了jdk1.7.0_80jdk1.8.0_73两个版本的JDK,而环境变量中的JAVA_HOME指向的是jdk1.7.0_80

解决方法就是修改JAVA_HOME指向jdk1.8.0_73即可。

注意,修改完成环境变量后,需要重启一下Android Studio,以及Windows命令行窗口。否则环境变量不生效。

Android Studio编译出的APK中一直包含android:debuggable="true"

最近遇到一个比较奇葩的事情,就是编译出来的APKAndroidManifest.xml中的application标签中一直包含android:debuggable="true"。不管是release版本,还是debug版本,不管如何设置,最终生成的文件中的调试选项一直是处于开启状态。

一时间竟然有些无从下手的感觉。首先确认我们自己的配置文件是没有问题的,那么这个现象一定是引入了某个aar中引入的AndroidManifest.xml中存在这个android:debuggable="true",导致Android Studio在最终合并AndroidManifest.xml文件的时候,把这个选项给合并进来了。

那么我们既然已经知道引入的地方,因此就只需要针对这种情况进行剖析即可了。

执行gradlew build之后,我们在app\build\intermediates\exploded-aar目录下面可以找到我们引入的全部的依赖的aar。我们只需要逐个分析引入的aar包的AndroidManifest.xml文件即可。

那么比较奇葩,是奇葩在哪里呢? 正常情况下,我们引入一个aar包,需要在build.gradle中声明如下:

compile 'com.taobao.android:new-cache:2.3.0.73@aar'

但是我们从真正的配置选项中看到的却是

compile 'com.taobao.android:new-cache:2.3.0.73'

按照一般的理解,我们如果没有设置@aar,那么Android Studio应该去下载对应的jar包才对。但是我们从实际的编译过程中看到,Android Studio在没有指定@aar的情况下,依旧默认去服务器上先尝试下载对应的aar,只有当aar找不到的时候才会去下载对应的jar包。而恰好,我们服务器上面两者都是存在的。于是出现了乌龙事件,本来只是需要下载jar包,结果却引入了一个莫名的aar包。而这个aar的开发同学又没有考虑到这种情况,以为用户只会用他提供的jar包。
解决方法还是比较简单的,就是明确告知Android Studio,我们需要的是jar包,也就是增加@jar。如下:

compile 'com.taobao.android:new-cache:2.3.0.73@jar'

相关参考链接


Android Studio: Why is Release Build debuggable?

Android Studio 2.1.3配置Robolectric-3.0,Powermock-1.6.5单元测试环境

Android Studio提供了比较方便的单元测试,但是由于Android系统的限制(ClassloaderGoogle自己实现的,Powermock无法修改底层的bytecode),目前Powermock还没办法直接在设备上执行测试,但是我们代码中难免存在一些静态对象,需要测试的时候,只能求助于PowermockRobolectric的组合。
具体的配置如下:
1.首先在需要测试的项目的build.gradle中声明需要使用PowermockRobolectric

testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile "org.powermock:powermock-classloading-xstream:1.6.5"
/*不可使用3.1.x版本,3.1.x版本无法与PowerMock配合测试,运行时候直接报错*/
testCompile 'org.robolectric:robolectric:3.0'

2.定义测试基类,在基类中声明一些必备的设置
AbsRobolectricPowerMockTest.java

import android.os.Build;

import org.junit.Rule;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;

/**
 * Created by longsky.wq on 2016/8/22.
 */
@PowerMockRunnerDelegate(RobolectricGradleTestRunner.class)
@RunWith(PowerMockRunner.class)
@Config(constants = BuildConfig.class,
        sdk = Build.VERSION_CODES.JELLY_BEAN_MR1)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*","javax.crypto.","java.security.*"})
abstract public class AbsRobolectricPowerMockTest {
    @Rule
    public PowerMockRule rule = new PowerMockRule();
}

3.定义真正的测试子类
DeckardActivityTest.java

import org.junit.Test;
import org.junit.Assert;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;

import static junit.framework.Assert.assertTrue;

@PrepareForTest(Static.class)
public class DeckardActivityTest extends AbsRobolectricPowerMockTest {
    @Test
    public void testStaticMocking() {
        /*如果如下断言失败,说明Robolectric环境没有初始化成功,说明配置存在问题*/
        Assert.assertNotNull(RuntimeEnvironment.application);
        
        PowerMockito.mockStatic(Static.class);
        Mockito.when(Static.staticMethod()).thenReturn("hello mock");

        assertTrue(Static.staticMethod().equals("hello mock"));
    }
}

注意,参考链接中的内容不可完全相信,按照参考链接中的配置(Robolectric-3.1.2+PowerMock-1.6.5),一般会遇到如下问题(看上去很怪异,其实是由于不同的classloader同时加载了相同的类,导致尽管类名是相同的,但是依旧无法进行类型转换):

com.thoughtworks.xstream.converters.ConversionException: Could not call org.apache.tools.ant.Project$AntRefTable.readObject() : Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project
---- Debugging information ----
class               : org.apache.tools.ant.types.FileSet
required-type       : org.apache.tools.ant.types.FileSet
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project
line number         : 167
-------------------------------
message             : Could not call org.apache.tools.ant.Project$AntRefTable.readObject()
cause-exception     : com.thoughtworks.xstream.converters.ConversionException
cause-message       : Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project
class               : org.apache.tools.ant.Project$AntRefTable
required-type       : org.apache.tools.ant.types.FileSet
converter-type      : com.thoughtworks.xstream.converters.reflection.SerializableConverter
path                : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project
line number         : 167
class[1]            : org.apache.tools.ant.Project
converter-type[1]   : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[2]            : org.robolectric.internal.dependency.MavenDependencyResolver
class[3]            : org.robolectric.internal.dependency.CachedDependencyResolver
class[4]            : org.robolectric.RobolectricGradleTestRunner
class[5]            : org.robolectric.RobolectricTestRunner$HelperTestRunner
class[6]            : org.robolectric.RobolectricTestRunner$HelperTestRunner$1
class[7]            : org.powermock.modules.junit4.rule.PowerMockStatement
class[8]            : org.powermock.modules.junit4.rule.PowerMockStatement$1
version             : not available
-------------------------------

	at com.thoughtworks.xstream.core.util.SerializationMembers.callReadObject(SerializationMembers.java:133)
	at com.thoughtworks.xstream.converters.reflection.SerializableConverter.doUnmarshal(SerializableConverter.java:455)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
	at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
	at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1206)
	at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1190)
	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1061)
	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1052)
	at org.powermock.classloading.DeepCloner.clone(DeepCloner.java:54)
	at org.powermock.classloading.AbstractClassloaderExecutor.executeWithClassLoader(AbstractClassloaderExecutor.java:56)
	at org.powermock.classloading.SingleClassloaderExecutor.execute(SingleClassloaderExecutor.java:67)
	at org.powermock.classloading.AbstractClassloaderExecutor.execute(AbstractClassloaderExecutor.java:43)
	at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:75)
	at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:250)
	at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:176)
	at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:49)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:142)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:148)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:140)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.withContextClassLoader(DelegatingPowerMockRunner.java:131)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:140)
	at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
	at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
	at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
Caused by: com.thoughtworks.xstream.converters.ConversionException: Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project
---- Debugging information ----
class               : org.apache.tools.ant.types.FileSet
required-type       : org.apache.tools.ant.types.FileSet
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project
line number         : 167
-------------------------------
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:439)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
	at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
	at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
	at com.thoughtworks.xstream.converters.reflection.SerializableConverter$2.readFromStream(SerializableConverter.java:337)
	at com.thoughtworks.xstream.core.util.CustomObjectInputStream.readObjectOverride(CustomObjectInputStream.java:120)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
	at java.util.Hashtable.readObject(Hashtable.java:996)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.thoughtworks.xstream.core.util.SerializationMembers.callReadObject(SerializationMembers.java:125)
	... 86 more

参考链接