App的打磨之路(上)

前言:

俗话说磨刀不误砍柴工,一个优秀的产品从一个不错的点子直到用户的手中,是需要一个团队不遗余力协同合作不断打磨出来的;同样,一个好的App除正常的代码编写外,还需要经过其他方面的不断打磨才能正式交互,最终到达用户的手中。该文主要讲述一个应用除开发外还需要进行哪些工作才能合格交互,在此抛砖引玉,希望对有需要的朋友一点启示!

该文由于内容较多故分为三篇博文来描述,主要内容包含:单元测试、性能分析、签名、混淆、APK瘦身、反编译、打包及加固,下文主要描述前面三个:单元测试、性能分析及签名。

一、单元测试

单元测试是编写测试代码,用来检测特定的、明确的、细颗粒的功能。单元测试不仅仅用来保证当前代码的正确性,更重要的是用来保证代码修复、改进或重构之后的正确性。对于想打造优秀产品的码农来说是必不可少的,虽然在大部分公司实现有居多困难。

一般来说,单元测试任务主要包括以下几个方面:

1. 接口功能测试

主要用来保证接口功能的正确性。

2. 数据结构测试

主要用来保证接口中的数据结构的正确性,比如变量有无初始值,是否溢出等。

3. 边界条件测试

边界条件判定是单元测试中最常用的,在开发中也是最容易遇到的BUG,边界条件判定的类型主要有以下几种情形:

- 变量是对象:如对象是否为NULL等;

- 变量是数值:数值边界:最小值、最大值、无穷小、无穷大,溢出边界:最小值-1、最大值+1,临近边界:最小值+1、最大值-1;

- 变量是字符串:字符串是否为空,字符串的长度进行数值变量的判定;

- 变量是集合:集合是否为空,集合的大小进行数值变量的判定;

4. 独立执行通路测试

主要保证代码的覆盖率,如语句覆盖:保证每一条语句都执行到,分支覆盖:保证每一个分支都执行到,条件覆盖:保证每一个条件都覆盖到true和false的情形,路径覆盖:保证每一个路径都执行到;

5. 异常处理通路测试

主要保证所有的异常都经过测试。

JUnit是Java单元测试框架,已经在Android Studio中默认依赖。目前主流的有JUnit3和JUnit4。JUnit3中,测试用例需要继承TestCase类。JUnit4中,测试用例无需继承TestCase类,只需要使用@Test等注解。以下通过一个实例来更好的展示单元测试过程:

先在应用下建立一个计算工具类,方便写单元测试:

package com.vise.note.util;

/**
 * 计算相关工具类
 * Created by xyy on 16/6/25.
 */
public class CalculatorUtil {
    public double plus(double a, double b){
        return a + b;
    }

    public double minus(double a, double b){
        return a - b;
    }

    public double multiply(double a, double b){
        return a * b;
    }

    public double divide(double a, double b) throws Exception {
        if(b == 0){
            throw new Exception("除数不能为零!");
        }
        return a / b;
    }

}

Android Studio提供了一个快速创建测试类的方法,只需在编辑器内右键点击CalculatorTest类的声明,选择Go to > Test,然后点击”Create a new test…”,到此会弹出两个选项,一个是androidTest,一个是test目录下,由于该测试不需要用到模拟器,可以运行在本地电脑Java虚拟机上,所以此处选择test目录下,随后在test与应用同包的目录下生成CalculatorUtilTest.java文件,内容如下(方法内部实现是手动添加的):

package com.vise.note.util;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Created by xyy on 16/6/25.
 */
public class CalculatorUtilTest {

    private CalculatorUtil calculatorUtil;

    @Before
    public void setUp() throws Exception {
        calculatorUtil = new CalculatorUtil();
    }

    @After
    public void tearDown() throws Exception {
        calculatorUtil = null;
    }

    @Test
    public void testPlus() throws Exception {
        assertEquals(6d, calculatorUtil.plus(1d, 5d), 0);
    }

    @Test
    public void testMinus() throws Exception {
        assertEquals(-4d, calculatorUtil.minus(1d, 5d), 0);
    }

    @Test
    public void testMultiply() throws Exception {
        assertEquals(5d, calculatorUtil.multiply(1d, 5d), 0);
    }

    @Test
    public void testDivide() throws Exception {
        assertEquals(0.2d, calculatorUtil.divide(1d, 5d), 0);
    }
}

最后就可以直接选择CalculatorUtilTest直接运行了。到此,单元测试就告一段落了,下面是讲述性能分析,这个也很重要哦!^_^

二、性能分析

1、Memory Monitor

在Android Studio中运行项目后,点击Android Monitor中的Monitor就可以看到如下图所示的Memory使用及CPU运行情况:

下面还可以查看GPU和Network的相关情况,其中NetWork的频繁使用是造成应用耗电的关键,70%左右的电量是被上报数据,检查位置信息,定时检索后台广告信息所使用掉的,如何平衡之间的使用也是很重要的。

2、Heap Snapshot

依据上面Memory Monitor描述,找到Memory中第三个图标“Dump Java Heap”,每次点击之后会生成一个.hprof的文件,点击一个.hprof文件,查看右侧的Analyzer Tasks,能看到两个选项,一个是‘Detect Leaeked Activites’,另一个是’Find Duplicate Strings’,点击右上角的绿色播放按钮,会自动分析heap dump去定位泄露的activity和重复的string,出现如下的Analysis Results:

从上面两幅图中可以看出,第一个选项表示查看的信息可以有三种类型:App heap/Image heap/Zygote heap.分别代表App堆内存信息,图片堆内存信息,Zygote进程的堆内存信息。还有一个选项可以选择Class List View和Package Tree View两种视图展示方式。

各属性中英文对照表

名称 意义
Total Count 内存中该类的对象个数
Heap Count 堆内存中该类的对象个数
Sizeof 物理大小
Depth 深度
Shallow size 对象本身占有内存大小
Retained Size 释放该对象后,节省的内存大小
Dominating Size 管辖的内存大小
3、LeakCanary
  • 使用方法

    在 build.gradle 中加入引用,不同的编译使用不同的引用:

dependencies {
   debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3‘
   releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3‘
}

在 Application 中:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}

应用运行起来后,LeakCanary会自动去分析当前的内存状态,如果检测到泄漏会发送到通知栏,点击通知栏就可以跳转到具体的泄漏分析页面。

  • 工作机制

    1、RefWatcher.watch() 创建一个 KeyedWeakReference 到要被监控的对象。

    2、然后在后台线程检查引用是否被清除,如果没有,调用GC。

    3、如果引用还是未被清除,把 heap 内存 dump 到 APP 对应的文件系统中的一个 .hprof 文件中。

    4、在另外一个进程中的 HeapAnalyzerService 有一个 HeapAnalyzer 使用HAHA 解析这个文件。

    5、得益于唯一的 reference key, HeapAnalyzer 找到 KeyedWeakReference,定位内存泄露。

    6、HeapAnalyzer 计算 到 GC roots 的最短强引用路径,并确定是否是泄露。如果是的话,建立导致泄露的引用链。

    7、引用链传递到 APP 进程中的 DisplayLeakService, 并以通知的形式展示出来。

    更多关于LeakCanary的使用介绍请参考:LeakCanary 中文使用说明

注:以上都是针对Android Studio IDE的性能分析方式。

三、签名

签名的前提得有签名文件,生成签名文件的方式大同小异,IDE基本都有这个功能,这里以Android Studio为列讲述生成签名文件的过程。选择工具栏Build->Generate Signed APK,打开后选择对应的module,点击next,如图所示:

点击Create new,进入如下界面:

信息注释
Key store path:签名文件路径
Password:签名库密码
Confirm:确认签名库密码
Alias:别名
Password:该别名下签名密码
Confirm:确认该别名下签名密码
Validity:认证年限
First and Last Name:你的全名
Organizational Unit:组织单位
Organization:组织
City or Locality:城市或地区
State or Province:川或省
Country Code:国家代码

按照指示填写对应信息,点击OK就生成了签名文件。

还一种方式是使用命令的方式创建,进入Java的bin目录下,如我的Java目录为:/Library/Java/Home/bin,通过keytool工具来创建keystore库,输入以下命令:

keytool -genkeypair -alias - xyy.keystore -keyalg RSA -validity 100 -keystore xyy.keystore
命令说明如下:
-genkeypair:指定生成数字证实
-alias:指定生成数字证书的别名
-keyalg:指定生成数字证书的算法  这里如RSA算法
-validity:指定生成数字证书的有效期
-keystore :指定生成数字证书的存储路径(这里默认在keytool目录下)

再按照提示一步步输入对应的信息,最后就生成了一个名为xyy.keystore的签名文件。

有了签名文件后,将签名文件放到对应需要签名的工程目录module下,再在module对应的build文件中添加如下签名信息(签名信息对应输入自己设置的秘钥信息):

android{
    ...
    signingConfigs {
        debug {
            storeFile file("xyy.keystore")
            storePassword "xyy"
            keyAlias "Note"
            keyPassword "xyy"
        }

        release {
            storeFile file("xyy.keystore")
            storePassword "xyy"
            keyAlias "Note"
            keyPassword "xyy"
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
            zipAlignEnabled true
            shrinkResources false
            signingConfig signingConfigs.debug
        }

        release {
            //是否混淆(注:如果混淆文件未配置使用false)
            minifyEnabled false
            //是否支持Zip Align
            zipAlignEnabled true
            //是否清理无用资源
            shrinkResources true
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
            //使用签名配置
            signingConfig signingConfigs.release

        }
    }
    ...
}

这样配置完后每次build工程生成的文件都会使用debug下的签名信息了,gradle配置详情可参考我的另一篇博客Android Studio常用Gradle操作

个人网站:http://www.xiaoyaoyou1212.com 欢迎吐槽围观!

时间: 2024-10-10 04:19:08

App的打磨之路(上)的相关文章

App的打磨之路(中)

前言:该文接上篇博文App的打磨之路(上),继续描述混淆及APK瘦身. 一.混淆 1.混淆原理 Java 是一种跨平台的.解释型语言,Java 源代码编译成中间"字节码"存储于 class 文件中.由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名.方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码.为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆. 混淆就是对发布出去的程序进行重新组织和处

瑞柏匡丞谈中国移动app的国际进阶路

当今3.0互联时代,已然形成了一个移动化,互动化,全球化的完整体系.瑞柏匡丞也在常年与国内外客户的交流沟通中有了自己的些许见解. 国内的移动产业的发展已然非常迅速,但也正是因为各类企业的不断崛起,能够最终占据一席之地的终归是少数.在国内市场,声誉和品牌影响力对于移动互联领域的发展作用不容小觑,粉丝运营从而带动的市场效益是做得风生水起.但在国外陌生环境下,初涉市场的品牌影响力可能几乎为0,而且对当地年轻群体的心理诉求的把握也远远难于国内,其粉丝影响力有多大还是未知数. 众所周知,国内市场虽然用户数

【Win 10应用开发】如何知道当前APP在哪个平台设备上运行

[Win 10应用开发]如何知道当前APP在哪个平台设备上运行 在做Win10开发的时候,我们可能经常会需要获得当前程序在在哪个平台设备上运行,用于UI和相关API的调用,那么可以通过什么方式知道当前APP运行的平台呢? 今天这里提供两个方法给大家做参考: 方法一:DeviceFamily 通过Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily,来获取当前的平台设备,目前只可以得到两个值Windows.Mobile或Wind

android app崩溃日志收集以及上传

源码获取请到github:https://github.com/DrJia/AndroidLogCollector 已经做成sdk的形式,源码已公开,源码看不懂的请自行google. 如果想定制适应自己app的sdk请自行fork. AndroidLogCollector android app崩溃日志收集sdk 1.0 作者:贾博士 崩溃日志收集方法: 1.LogCollector是lib包,在需要添加崩溃日志sdk的工程中导入此包. 2.导入lib后,在自己的工程的AndroidManife

JEPLUS之app功能创建与发布--上——JEPLUS软件快速开发平台

JEPLUS之app功能创建与发布--上 在前几天的文章我简单的介绍了在JEPLUS中创建APP今天我来再次介绍下APP创建以及怎么来查看我们的APP功能. 一.APP创建 1.首先我们的APP功能开发依赖于我们的平台功能,所以我们需要实现APP功能时 我们必须得实现平台上的功能.这样我们就可以实现我们的APP功能了. 这样点击选择我们的平台功能我们就可以实现我们的APP功能了. 查看原文及阅读更多 原文地址:http://blog.51cto.com/13797782/2136450

我们的APP海外推广之路,让下载量从几百个到上百万

摘要:绝对的真实经历,谈谈我们团队开发的APP是如何在海外进行推广,如何让下载量从几百个到后面的上百万.因为我们的预算有限,所以是不可能投大把大把的钱去推广,最后我们选择了自己花时间再加上很少的投入这种方式达到了不俗的效果! 开发经历我在这儿就不多说了,不同的团队有不同的创意,最后的成果也不同,当然开发的过程也不同,唯一相同的可能是都尝遍了酸甜苦辣.经历过大半年的时间,我们终于完成了自己的产品,又经过一段时间的审核,我们的APP最后成功上线了(这儿我就不说名字了,不然又要说我推广自己的产品了),

Https安全协议在手机App与后台服务通信上的应用

引言 App要上苹果支付渠道,苹果支付票据容易被人篡改.伪造,造成平台收益与实际交易额对不上:且由于苹果支付平台暂时没有对账功能,造成很难区分真伪:只能提高应用的安全性,防止支付信息泄露或被篡改,因此打算引入https这种安全传输协议. 什么是Https,与Http有哪儿些异同 HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入SSL层,HTTPS的

[转]---UWP中如何判断当前APP在哪个平台设备上运行

在做Win10开发的时候,我们可能经常会需要获得当前程序在在哪个平台设备上运行,用于UI和相关API的调用,那么可以通过什么方式知道当前APP运行的平台呢? 今天这里提供两个方法给大家做参考: 方法一:DeviceFamily 通过Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily,来获取当前的平台设备,目前只可以得到两个值Windows.Mobile或Windows.Desktop,分别代表手机和pc(平板) (当然以后没

常见的八种导致 APP 内存泄漏的问题(上)

百度搜索:小强测试品牌 QQ群:138269539 像 Java 这样具有垃圾回收功能的语言的好处之一,就是程序员无需手动管理内存分配.这减少了段错误(segmentation fault)导致的闪退,也减少了内存泄漏导致的堆空间膨胀,让编写的代码更加安全.然而,Java 中依然有可能发生内存泄漏.所以你的安卓 APP 依然有可能浪费了大量的内存,甚至由于内存耗尽(OOM)导致闪退. 传统的内存泄漏是由忘记释放分配的内存导致的,而逻辑上的内存泄漏则是由于忘记在对象不再被使用的时候释放对其的引用导