读书笔记——小点积累(全局Context、日志工具、编写测试用例、生成正式签名apk)

获取全局Context

1、直接获取的方式

getApplicationContext()

2、利用Application类

每当程序启动时,系统会自动将这个类初始化。

public class MyApplication extends Application {
    private static Context context;

    @Override
    public void onCreate() {
        context = getApplicationContext();
    }
    public static Context getContext() {
        return context;
    }
}

重写了父类的 onCreate()方法,并通过调用 getApplicationContext()方法得到了一个应用程序级别的 Context,然后又提供了一个静态的 getContext()方法,在这里将刚才获取到的 Context进行返回。

我们需要告知系统,当程序启动的时候应该初始化 MyApplication 类,而不是默认的 Application类。这一步也很简单,在 AndroidManifest.xml 文件的标签下进行指定就可以了,代码如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.networktest"
    android:versionCode="1"
    android:versionName="1.0" >
    ……
    <application
        android:name="com.example.networktest.MyApplication"
        …… >
        ……
    </application>
</manifest>

!!!注意这里在指定 MyApplication 的时候一定要加上完整的包名,不然系统将无法找到这个类。

调用

在需要使用全局Context的地方:

MyApplication.getContext()

比如:

Toast.makeText(MyApplication.getContext(), "network is unavailable", Toast.LENGTH_SHORT).show();

定制自己的调试工具——log工具类

public class LogUtil {
    public static final int VERBOSE = 1;
    public static final int DEBUG = 2;
    public static final int INFO = 3;
    public static final int WARN = 4;
    public static final int ERROR = 5;
    public static final int NOTHING = 6;
    public static final int LEVEL = VERBOSE;

    public static void v(String tag, String msg) {
        if (LEVEL <= VERBOSE) {
            Log.v(tag, msg);
        }
    }

    public static void d(String tag, String msg) {
        if (LEVEL <= DEBUG) {
            Log.d(tag, msg);
        }
    }

    public static void i(String tag, String msg) {
        if (LEVEL <= INFO) {
            Log.i(tag, msg);
        }
    }

    public static void w(String tag, String msg) {
        if (LEVEL <= WARN) {
            Log.w(tag, msg);
        }
    }

    public static void e(String tag, String msg) {
        if (LEVEL <= ERROR) {
            Log.e(tag, msg);
        }
    }
}

让LEVEL等于 VERBOSE 就可以把所有的日志都打印出来,让 LEVEL 等于 WARN 就可以只打印警告以上级别的日志,让 LEVEL等于 NOTHING就可以把所有日志都屏蔽掉。使用了这种方法之后,刚才所说的那个问题就不复存在了,你只需要在开发阶段将LEVEL指定成 VERBOSE,当项目正式上线的时候将 LEVEL指定成 NOTHING就可以了。

编写测试用例

1、创建测试工程
Android Studio:已经自动生成
Eclipse: File→New→Other,会打开一个对话框,展开 Android目录,在里面选中 Android Test Project。一直Next并选择要测试的项目,结束。

在Eclipse中这个测试工程,有自己的清单文件,会生成如下:

<instrumentation
    android:name="android.test.InstrumentationTestRunner"
    android:targetPackage="com.example.broadcastbestpractice" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >

    <uses-library android:name="android.test.runner" />
</application>

和标签是自动生成的,表示这是一个测试工程,在标签中还通过 android:targetPackage属性指定了测试目标的包名。

2、进行单元测试
BroadcastBestPractice 项目中有一个 ActivityCollector 类,主要是用于对所有的 Activity进行管理的,那么我们就来测试这个类吧。
1、首先在 BroadcastBestPracticeTest项目中新建一个ActivityCollectorTest 类,并让它继承自 AndroidTestCase,然后重写 setUp()和 tearDown()方法,如下所示。


public class ActivityCollectorTest extends AndroidTestCase {
    @Override
    protected void setUp() throws Exception {
        super.setUp();
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }
}

> 其中 setUp()方法会在所有的测试用例执行之前调用,可以在这里进行一些初始化操作。tearDown()方法会在所有的测试用例执行之后调用,可以在这里进行一些资源释放的操作。(感觉谷歌项目的测试都是自动有这两个函数,哈哈,和chromebook测试程序一样一样的)。

2、测试用例

> 只需要定义一个以 test开头的方法,测试框架就会自动调用这个方法了。然后我们在方法中可以通过断言(assert)的形式来期望一个运行结果,再和实际的运行结果进行对比,这样一条测试用例就完成了。测试用例覆盖的功能越广泛,程序出现 bug 的概率就会越小。

比如说 ActivityCollector 中的 addActivity()方法是用于向集合里添加活动的,那么我们就可以给这个方法编写一些测试用例,代码如下所示:

public class ActivityCollectorTest extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
}

public void testAddActivity() {
    assertEquals(0, ActivityCollector.activities.size());
    LoginActivity loginActivity = new LoginActivity();
    ActivityCollector.addActivity(loginActivity);
    assertEquals(1, ActivityCollector.activities.size());
}

@Override
protected void tearDown() throws Exception {
    super.tearDown();
}

}

现在这个测试用例其实只是覆盖了很少的情况而已,我们应该再编写一些特殊情况下的断言,看看程序是不是仍然能够正常工作。修改 ActivityCollectorTest中的代码,如下所示。

public void testAddActivity() {
    assertEquals(0, ActivityCollector.activities.size());
    LoginActivity loginActivity = new LoginActivity();
    ActivityCollector.addActivity(loginActivity);
    assertEquals(1, ActivityCollector.activities.size());
    ActivityCollector.addActivity(loginActivity);
    assertEquals(1, ActivityCollector.activities.size());
}

这里我们又调用了一次 addActivity()方法来添加活动,并且添加的仍然还是LoginActivity。连续添加两次相同活动的实例,这应该算是一种比较特殊的情况了。这时我们觉得 ActivityCollector 有能力去过滤掉重复的数据,因此在断言的时候认为目前ActivityCollector 中的活动个数仍然是 1。

从这个测试用例中我们发现,addActivity()方法中的代码原来是不够健壮的,这个时候就应该对代码进行优化了。修改 ActivityCollector 中的代码;

public static void addActivity(Activity activity) {
    if (!activities.contains(activity)) {
        activities.add(activity);
    }
}

生成正式签名apk

我们通过编程软件(eclipse , android studio)来将程序安装到手机上,背后工作流程:将程序代码打包成一个APK文件,再将这个文件传输到手机上,再执行安装操作。

Android系统会将所有的APK文件识别为应用程序的安装包。但并不是所有APK文件都能成功安装到手机上的,系统要求只有签名后的APK文件才可以安装。因此,我们还需要对生成的APK文件进行前面才行。

Eclipse默认keystore签名——开发阶段

Eclipse 导航栏的 Window→Preferences→Android→Build 可以查看到这个默认
keystore 文件的位置
这里写图片描述
所有通过 Eclipse来运行的程序都是使用了这个 debug.keystore文件来进行
签名的。不过这仅仅适用于开发阶段而已。

Eclipse——生成一个带有正式签名的APK文件

(1) 右击 项目→Android Tools→Export Signed Application Package
(2)直接点击 Next就好。然后会弹出一个选择keystore 文件的对话框,由于目前我们还没有一个正式的 keystore 文件,所以应该选择 Create new keystore。接着指定一下 keystore 的文件名和路径,并输入密码
(3)继续点击 Next,这时会要求输入一系列创建 keystore 文件所必要的信息,根据自己的实际情况进行填写就行了。注意,在 Validity 那一栏填写的是 keystore 文件的有效时长,单位是年,一般建议时间可以填得长一些。
(4)继续点击 Next,这时就要选择 APK文件的输出地址了。现在点击 Finish,然后稍等一段时间,keystore 文件和 APK文件就都会生成好了,并且这个 APK文件已经是签过名的了。另外,由于我们已经有了 项目.keystore 这个文件,以 后 再 给该项目 打 包 的 时 候 就 不 用 创 建 新 的 keystore 文 件 了 , 只 需 要 选 择该项目.keystore 文件,并输入正确的密码即可。

android studio 签名

http://jingyan.baidu.com/article/5552ef47e5d18d518efbc96b.html
(1)首先打开Android Studio选择Build -> Generate Signed APK…
(2)弹出对话窗口,如果没有key,就新建一个key。
这里写图片描述
(3)新建一个key,可根据自己需要填写相关项.路径选择最好选择项目根目录就可以了。
(4)单击next下一步,Finish完成。过一会会提示签名打包成功。在这里会选择输出目录和build打包方式。上面选择打包方式release,为什么不选择debug,debug默认不签名,而且对一些文件图片的格式校验比较松,还有就是一些string.xml文件或其他xml文件命名校验不是很严格,不必进行强制编译。
注意:默认的输出目录是在app下,如果多的话这个会占目录结构的很大一部分,所以最好不要选择这个目录结构,选择as已经为我们准备好的目录下:

app\build\outputs\apk下

(5)查看签名文件
注意,这里的key是一个.jks结尾的文件。和Eclipse不一样。只是加密方式不一样,其他的不影响。
打开cmd,进入签名文件所在位置,利用keytool:

keytool -list -v -keystore xxx.jks

然后输入密码,即可。
http://www.bubuko.com/infodetail-918228.html

android studio多渠道打包

http://blog.csdn.net/jjwwmlp456/article/details/45057067
http://www.open-open.com/lib/view/open1430730874085.html
http://www.cnblogs.com/0616–ataozhijia/p/4203997.html
http://my.oschina.net/aibenben/blog/373596
(1)目的:分渠道打包目的是为了针对不同市场做出不同的一些统计,数据分析,收集用户信息。
(2)方法:(以友盟为例子)
渠道信息一般在 AndroidManifest.xml中修改以下值:

<meta-data android:name="UMENG_CHANNEL" android:value="wandoujia" />

首先你必须在AndroidManifest.xml中的meta-data修改以下的样子:

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}" />

其中${UMENG_CHANNEL_VALUE}中的值就是你在gradle中自定义配置的值。

build.gradle文件就利用productFlavors这样写:

productFlavors {

wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}

baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}

c360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "c360"]
}

uc {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "uc"]
}

}

其中[UMENG_CHANNEL_VALUE: “wandoujia”]就是对应${UMENG_CHANNEL_VALUE}的值。

(3)后来发现上面的重复代码太多,就在网上又发现了一个更简洁的写法

productFlavors {

wandoujia {}
baidu {}
c360 {}
uc {}

productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}

}

其中name的值对相对应各个productFlavors的选项值,这样就达到自动替换渠道值的目的了。

这样生成apk时,选择相应的Flavors来生成指定渠道的包就可以了,而且生成的apk会自动帮你加上相应渠道的后缀,非常方便和直观。大家可以自己反编译验证。

用命令打包

(4)一次生成所有渠道包
在android studio底栏中有个命令行工具Terminal,打开后就CMD可以自动切换到当前项目的目录下。

有的项目下会有graldew.bat这个文件,你就可以输入这个命令:
gradlew assembleRelease
就可以一次性生成所有的渠道包了。
不过我一般不建议大家使用这个命令,gradlew这个命令的gralde的版本无法控制,有时候会莫名其妙的下载老版本的gradle,所以我个人推荐大家使用以下的用法。

(4-1)先找到gralde的根目录,在系统变量里添加两个环境变量:

变量名为:GRADLE_HOME,变量值就为gradle的根目录;
比如:C:\Users\yazhou\.gradle\wrapper\dists\gradle-2.1-all\27drb4udbjf4k88eh2ffdc0n55\gradle-2.1

(4-2)还有一个在系统变量里PATH里面添加gradle的bin目录

比如C:\Users\yazhou\.gradle\wrapper\dists\gradle-2.1-all\27drb4udbjf4k88eh2ffdc0n55\gradle-2.1\bin

(4-3)这里配置完成了,接着在Terminal中敲下 gradle assembleRelease就可以一次性生成所有的渠道包了。

所有生成的apk在项目的build\outputs\apk下。

(5)只是想生成单个渠道的包
(5-1)(as右边侧边栏Gradle,点击打开,gradle projects,把所有子目录扩展,会发现app下面的task目录),会发现模块多了很多任务。
这里写图片描述

此时可以直接双击该任务生成对应的apk(注意release),也可以用命令行单独生成,比如

gradle assembleWandoujiaRelease
用工具打包

和上面说的打包是一样的,只是在最后一步的时候,选择Flavors里面就会有信息,你在build.gradle文件中配置的平台。
这里写图片描述

最后生成带有各个平台的apk文件。

自动签名、混淆、打包、注入多个渠道。

关于多渠道,其实就是定义了多个flavor。用manifestPlaceholders配置,替换manifest中的占位符${}。

apply plugin: 'com.android.application'  

/*  
定义一个方法,仅def声明时,返回类型任意(自动判断)  
   可以将返回值直接写成String 或def String  
gradle支持groovy语言,groovy默认引入的包有:  
  java.io.* java.lang.* java.math.BigDecimal java.math.BigInteger  
  java.net.* java.util.* groovy.lang.* groovy.util.*  
 */  
def String computeVersionName() {  
    return "8.8.8"  
}  


android {  
    compileSdkVersion 22  
    buildToolsVersion "22.0.1"  


    defaultConfig {  
        applicationId "com.stone.myapplication"  
        minSdkVersion 8  
        targetSdkVersion 22  
        versionCode 1  
        versionName computeVersionName() //使用外部定义的方法  
        /*  
        manifestPlaceholders   
            manifest中使用占位符,如:<... android:name="${YOUR_APP_KEY}" >  
            以[key-value]形式替换:[YOUR_APP_KEY:"value"]  
        */  
        manifestPlaceholders = [YOUR_APP_KEY: "友盟后台的appkey"]  
    }  

    signingConfigs { //gradle assembleRelease  
        /*  
           可以定义多个签名配置项,如下面的myConfig  
         */  
        myConfig {  
            storeFile file("stone.keystore")  
            storePassword "mypasswd"  
//          storePassword System.console().readLine("\nKeystore password: ")  
            keyAlias "stone"  
            keyPassword "mypasswd"  
//          keyPassword System.console().readLine("\nKey password: ")  
        }  
    }  

    buildTypes {  
        /*  
            可以配置多个buildType项,如下面的release,debug,aabbcc  
         */  
        release {  
            minifyEnabled true  //译:使变小enabled。   即启用混淆器  
            //混淆文件:sdk/tools/proguard/proguard-android.txt 和 当前module下的proguard-rules.pro  
//            proguardFiles  getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro'  
            //getDefaultProguardFile('proguard-android.txt'),  
            //getDefaultProguardFile('proguard-android-optimize.txt'),  
            signingConfig signingConfigs.myConfig  
            zipAlignEnabled true    //混淆后的zip优化,默认为true,可不写。当不显示配置为true时,不会生成unaligned.apk  
        }  
        debug {  
            debuggable true  //启用debug的buildType配置  
        }  

        aabbcc {//自定义配置,未配置签名项,所以会生成未签名apk  
            multiDexEnabled true  
        }  
    }  

    productFlavors {  
        /*  
          productFlavors-产品风格:  
                即不同产品的配置,它会基于上面的公共配置项defaultConfig  
                下面的配置项与buildTypes{}中的配置项,成类似sql中的全联(full join)关系  
                 当执行 $gradle build   命令后,会生成:  
                    module-flavor1-release-unaligned.apk  
                    module-flavor1-release.apk  
                    module-flavor1-debug-unaligned.apk  
                    module-flavor1-debug.apk  
                    module-flavor1-aabbcc.apk  
                    ...flavor2...apk  

          applicationId 用于标识 在谷歌Play商店上的唯一标识 默认不配置,则与app的AndroidManifest.xml中的package一致  
                仅替换<manifest>中的package属性值,其它不受影响  

         */  

        flavor1 {  
            proguardFiles 'proguard-rules.pro'  
            applicationId "com.stone.myapplication.pro" //比如 专业版  
            manifestPlaceholders = [channelID: "百度应用平台"]  
        }  

        flavor2 {  
            proguardFile 'proguard-rules.pro'  
            applicationId "com.stone.myapplication.free" //比如 免费版  
            manifestPlaceholders = [channelID: "豌豆夹"]  
        }  
    }  

}  

dependencies {  
    //  Local binary dependency  本地jar包  
    compile fileTree(dir: 'libs', include: ['*.jar'])  
    // Module dependency 引用android-library项目  
    compile project(':eventbuslib')  
    /*  
      Remote binary dependency  download to local   group:name:version   
      配置远程仓库中的jar包,打包时,检查本地有没有,若没有则下载到本地。  
     */  
    compile 'com.android.support:appcompat-v7:22.0.0'  
    compile 'com.android.support:support-v4:22.0.0'  
    compile 'com.android.support:cardview-v7:22.0.0'  
    compile 'com.android.support:recyclerview-v7:22.0.0'  
}  
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.stone.myapplication">  

    <application  
        android:allowBackup="true"  
        android:icon="@mipmap/ic_launcher"  
        android:label="@string/app_name"  
        android:theme="@style/AppTheme">  
        <activity  
            android:name=".MainActivity"  
            android:label="@string/app_name">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  

                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  

            <meta-data  
                android:name="UMENG_APPKEY"  
                android:value="${YOUR_APP_KEY}" />  
            <meta-data  
                android:name="channelName"  
                android:value="${channelID}" />  
        </activity>  
    </application>  

</manifest>  

Android-Gradle DSL 简介

在android{}块中可以包含以下直接配置项:

defaultConfig{} 默认配置,是ProductFlavor类型。它共享给其他ProductFlavor使用
sourceSets{ } 源文件目录设置,是AndroidSourceSet类型。
buildTypes{ } BuildType类型
signingConfigs{ } 签名配置,SigningConfig类型
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
aaptOptions{ } aapt配置,AaptOptions类型
lintOptions{ } lint配置,LintOptions类型
dexOptions{ } dex配置,DexOptions类型
compileOptions{ } 编译配置,CompileOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。 用于设定 jacoco版本
splits{ } Splits类型。

在DSL文档中,以上每个类型都有它的详细配置选项
Gradle的DSL,领域特定语言(domain-specific languages,简称DSL),地址:http://gradle.org/docs/2.3/dsl/
Gradle的用户指南,地址:http://gradle.org/docs/2.3/userguide/userguide.html
Android-Gradle-DSL Android结合Gradle的DSL
下载地址:https://developer.android.com/shareables/sdk-tools/android-gradle-plugin-dsl.zip
简单介绍Android-Gradle构建插件的官方地址:https://developer.android.com/tools/building/plugin-for-gradle.html
详细介绍Android-Gradle构建插件的官方地址:http://tools.android.com/tech-docs/new-build-system

Android 多渠道打包渠道验证

转自:http://my.oschina.net/aibenben/blog/373596
这种东西看不大懂,就直接搬了。
准备工具:

1.在eclipse安装 fatjar插件,为的就是生成.jar文件(推荐直接在线更新,更新地址为http://kurucz-grafika.de/fatjar)

在线安装步骤:

eclipse菜单栏 help >intall New software>Add>

填写name 和url

name:任意起个,如 fat

url:这个是fat jar的地址 输入http://kurucz-grafika.de/fatjar

2.apkTool工具 (链接: http://pan.baidu.com/s/1bnxsCr1 密码: pesf)

工具准备好后就开始干活了。

1.在eclipes里面,创建一个java项目(链接: http://pan.baidu.com/s/1bnAPLev 密码: p262)。

然后创建两个java文件。
这里写图片描述

说实话,我也没仔细看,直接copy过来,然后先跑起来,再去修改。我把我改过后的地方贴出来,也是大家用的时候需要注意的地方
这里写图片描述

2.把这个java项目打包成.jar文件

a.点击项目–>右键.如果你的fat插件安装好了,就会有一个build fat jar

这里写图片描述

b.这里一定要注意,第一次,可能Main-Class为空,大家一定要选择,Main.java文件,可以理解为启动文件嘛,因为里面有main方法—Finish
这里写图片描述
.

c.就会发现在项目下生成了一个.jar文件。这就是我们要的。
这里写图片描述
.

3.写一个批处理文件,批量处理脚本,之前我也从没写过什么批处理文件,就是一个.bat文件,跟我一样不了解的也不用怕,

这里写图片描述

创建一个文本文件

代码贴出来,直接copy嘛 当然,我们里面需要写代码,我直接贴出来了啊

@echo off
::java -jar VeidyDemoJava_fat.jar %var%
java -jar VeidyDemoJava_fat.jar C:\apk
echo.&echo 请按任意键退出...&pause>nul
exit

,然后另存为,文件名以.bat ,all.类型文件,

这里写图片描述

这样批处理文件就搞定了。只需要双击打开就能运行。

一切准备就绪。

我要验证的apk放在c盘apk文件夹,这是我要验证的apk

这里写图片描述

我建议这样。我们创建一个文件夹apkTols,然后,把test.bat,VeidyDemoJava_fat.jar还有apkTool解压出来的三个文件 放在apkTols文件夹
这里写图片描述

然后直接双击test就行啦。

这里写图片描述

大功告成.

最后,如果你用的是友盟统计,如果你跟我一样习惯了拿来主义。那就请直接下载VeidyapkTol(链接: 链接: http://pan.baidu.com/s/1c0fFDZy 密码: c9xj).然后在c盘根目录解压,会有两个文件夹,把你要验证的apk放到apk文件夹,然后打开apkTol文件夹里面,直接双击test.bat就行。就是这么任性。

这里写图片描述

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值