IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Gradle混淆+打包Jar包基础

    summer发表于 2016-06-20 15:13:10
    love 0

    本文为原创文章,转载请注明出处。  

    文章最后会附带源码下载地址,有需要的朋友可下载。

    通常我们编写Android APP时有这样的需求:(1)代码混淆;(2)模块化;(3)向第三方提供JAR包。下面将以实例的形式向初学Android或开始使用AndroidStudio(AS)的朋友介绍下这几部分。

    引述:

    (1)AS采用了Gradle的构建工具,可以让我们很方便的对我们的APP进行配置,比如版本、支持最低API level 、代码混淆文件、第三方库等等,具体语法请查考其他朋友的文章。

    (2)AS提供了模块编程,便于我们对APP进行分层和理清架构,个人推荐初学者可以参考下这篇文章。

    实例正文:

    本文实例仅作为演示使用,重点是演示代码混淆和打包JAR,所以功能都进行了简化并省略了很多逻辑代码。

    基本需求:接受用户的登录请求,模拟完成向服务端发起登录请求,并提示登录结果。

    一、创建项目

    项目目录结构:

    个人习惯将各模块创建为平级,模块(android library)描述:

    app:用户模块,用户交互界面、用户资源等   model:实体模块     player:核心业务模块  utils:辅助类模块。

    提示:创建模块时注意模块类型为Android Library,否则会对后面的一些功能会有影响。

     

    二、代码编写

    (1)model模块

    用户登录信息实体:

     

    1 package xiaoshubao.model;
    2
    3 /**
    4 * 作者: 小书包
    5 * 日期: 2016/6/16
    6 * 版本: V1.0
    7 * 说明:
    8 */
    9 public class UserModel {
    10 String userName;
    11 String pwd;
    12
    13 public void setUserName(String userName) {
    14 this.userName = userName;
    15 }
    16
    17 public void setPwd(String pwd) {
    18 this.pwd = pwd;
    19 }
    20
    21 public String getUserName() {
    22 return userName;
    23 }
    24
    25 public String getPwd() {
    26 return pwd;
    27 }
    28 }

    View Code

     

      其他实体不再贴代码,model层最终的代码结构如下:

    HttpMsgCallback:http回调请求接口

    Parent:无实际意义类,代码混淆时需要

    UserLoginCallback:用户登录结果回调接口

    (2)utils模块:

    网络访问辅助类(HttpUtils):

    1 package xiaoshubao.utils;
    2
    3 import java.util.HashMap;
    4 import java.util.Map;
    5
    6 import xiaoshubao.model.HttpMsgCallback;
    7 import xiaoshubao.model.Parent;
    8
    9 /**
    10 * 作者: 小书包
    11 * 日期: 2015/12/18
    12 * 版本:V1.0
    13 * 说明:与服务端Http通信
    14 */
    15 public class HttpUtils implements Parent {
    16 private static final String TAG = "HttpUtils";
    17
    18 /**
    19 * 发送Post请求到服务器 HTTP
    20 *
    21 * @param strUrlPath 服务器地址
    22 * @param params 请求体参数
    23 * @return 错误码
    24 */
    25 private static String httpPostData(String strUrlPath, Map<String, String> params) {
    26
    27 return "true";
    28 }
    29
    30 /**
    31 * 向http服务器发出注册消息
    32 * @param serverUrl 服务器地址
    33 * @param params 请求体参数
    34 * @param httpMsgCallback 执行结果回调
    35 */
    36 public static void sendPostMsgToServer(final String serverUrl, final HashMap params, final HttpMsgCallback httpMsgCallback) {
    37 Thread thread = new Thread(new Runnable() {
    38 @Override
    39 public void run() {
    40 try {
    41 Thread.sleep(2*1000);//当前线程睡眠两秒钟模拟发送网络请求
    42 } catch (InterruptedException e) {
    43 e.printStackTrace();
    44 }
    45 String result = HttpUtils.httpPostData(serverUrl, params);
    46 httpMsgCallback.httpPostCallBack(result);
    47 }
    48 });
    49 thread.start();
    50 }
    51 }

    View Code

     

    (3)player模块

     UserLogin类(用户登录业务类):

     

    1 package xiaoshubao.player;
    2
    3 import java.util.HashMap;
    4
    5 import xiaoshubao.model.HttpMsgCallback;
    6 import xiaoshubao.model.Parent;
    7 import xiaoshubao.model.UserLoginCallback;
    8 import xiaoshubao.model.UserModel;
    9 import xiaoshubao.utils.HttpUtils;
    10
    11 /**
    12 * 作者: 小书包
    13 * 日期: 2016/6/16
    14 * 版本: V1.0
    15 * 说明:
    16 */
    17 public class UserLogin implements Parent {
    18 UserLoginCallback userLoginCallback;
    19 public UserLogin(UserLoginCallback userLoginCallback){
    20 this.userLoginCallback=userLoginCallback;
    21 }
    22
    23 /**
    24 * 用户登录
    25 * @param user 用户信息
    26 */
    27 public void login(UserModel user){
    28 userLogin(user);
    29 }
    30 private void userLogin(UserModel user){
    31 HashMap hashMap=new HashMap();
    32 hashMap.put("userName",user.getUserName());
    33 hashMap.put("pwd",user.getPwd());
    34 HttpUtils.sendPostMsgToServer("XXXXX", hashMap, httpMsgCallback);
    35 }
    36 HttpMsgCallback httpMsgCallback=new HttpMsgCallback() {
    37 @Override
    38 public void httpPostCallBack(String json) {
    39 if (json.contains("true")&&null!=userLoginCallback){
    40 userLoginCallback.loginResult(true);
    41 }else if (null!=userLoginCallback){
    42 userLoginCallback.loginResult(false);
    43 }
    44 }
    45 };
    46 private void fun1(){}
    47 private void fun2(){}
    48 }

    View Code

     

    三、代码混淆

      AS中进行代码混淆需要在build.gradle文件和proguard-rules.pro文件中进行设置(可以通过jd-gui工具对比混淆前后效果):

    (1)build.gradle文件

    minifyEnabled:表示是否开启混淆,默认为false

    proguardFiles:混淆配置文件,一般就采用项目中默认的proguard-rules.pro文件。

    (2)proguard-rules.pro文件

    混淆设置,具体可参考progurad官网。

    注意图中红框部分,因为所有jar包都要求有对外接口(没有对外接口的模块一般也没什么意义),有多种种方式设置对外接口类:

    a:-keep public class *,例如:

    -keep public class * {
    public protected *;
    }

    b:如图所示。

    因为一个模块一般有很多类文件,混淆时我们希望除对外接口类的其他所有类文件的类名也进行混淆,那么就可以单独创建一个基类或接口,让对外的接口类继承该基类或接口。

    c:-keep public class XXX,特定类不混淆,例如:

    -keep public class xiaoshubao.player.UserLogin{
    public protected *;
    }

    四、打包JAR包

    (1)proguard-rules.pro配置

    配置生成JAR包的基本属性,如下:

    上述代码很简单不再叙述。

    (2)生成JAR包

    CMD命令行中切换到当前项目目录下,执行gradlew makeJar 命令。

    顺利的话会生成JAR包,如果是第一次采用gradlew生成,可能需要在线更新相关包,大约几分钟时间。

    如果配置、类引用出现错误,CMD窗口会提示,请根据具体的错误提示做修改。

    (3)JAR包合并

    gradlew makeJar命令会在model、uitls、palyer目录下分别生成这三个模块的JAR包,那么如果我们需要向第三方提供SDK,三个JAR包可能会不太方便,所以就有了合并为一个JAR包的需求。

    我们知道JAR包其实就是普通的压缩包而已,所以对三个JAR包进行解压后文件如下:

    注意:META-INF配置文件,该项目对palyer、utils模块进行了混淆而model模块未混淆(也可通过配置进行混淆),所以只有一个META-INF文件生成,如果有多个模块未混淆时生成了多个META-INF文件,采用本文方法进行JAR包合并会出问题。

    xiaoshubao文件夹下的目录文件如下:

     

     一起压缩META-INF、xiaoshubao文件生成zip文件,重命名为.jar文件,结果如下:

    五、第三方使用

     将MyUserManager.jar包导入测试项目(非JAR包源码项目)中,如下:

    提示:有时在JAR包前面没有向下的三角符号也无法点开JAR包查看里面的类文件,且使用JAR包里的类时会报错,此时重启该项目应该就可以出现如上图所示的效果。

    (1)登录界面:

    (2)登录代码:

    1 package xiaoshubao.jartest;
    2
    3 import android.content.Context;
    4 import android.os.Bundle;
    5 import android.os.Message;
    6 import android.support.v7.app.AppCompatActivity;
    7 import android.view.View;
    8 import android.widget.EditText;
    9 import android.widget.Toast;
    10
    11 import xiaoshubao.model.UserLoginCallback;
    12 import xiaoshubao.model.UserModel;
    13 import xiaoshubao.player.UserLogin;
    14
    15 public class MainActivity extends AppCompatActivity {
    16 Context context;
    17 MyHandler handler;
    18 @Override
    19 protected void onCreate(Bundle savedInstanceState) {
    20 super.onCreate(savedInstanceState);
    21 setContentView(R.layout.activity_main);
    22 context = this;
    23 handler = new MyHandler();
    24 }
    25 public void btn_loginClick(View v) {
    26 UserLogin userLogin = new UserLogin(userLoginCallback);
    27 UserModel userModel = new UserModel();
    28 String userName = ((EditText) findViewById(R.id.etUserName)).getText().toString().trim();
    29 userModel.setUserName(userName);
    30 String pwd = ((EditText) findViewById(R.id.etPwd)).getText().toString().trim();
    31 userModel.setPwd(pwd);
    32 userLogin.login(userModel);
    33 }
    34
    35 UserLoginCallback userLoginCallback = new UserLoginCallback() {
    36 @Override
    37 public void loginResult(boolean result) {
    38 Message msg = Message.obtain();
    39 msg.what = 7634;
    40 if (result) {
    41 msg.obj = "登录成功!";
    42 } else {
    43 msg.obj = "登录失败!";
    44 }
    45 handler.sendMessage(msg);
    46 }
    47 };
    48
    49 public class MyHandler extends android.os.Handler {
    50 @Override
    51 public void handleMessage(Message msg) {
    52 switch (msg.what) {
    53 case 7634:
    54 Toast.makeText(context, msg.obj.toString(), Toast.LENGTH_LONG).show();
    55 }
    56 }
    57 }
    58 }

    View Code

     

    (3)运行效果

     

    代码混淆是最简单、最基础的Android APP安全保障,后续将还会介绍其他的关于APP安全相关技术。

    本实例DEMO下载地址(MyApplication4 源码项目,JarTest模拟第三方项目)。



沪ICP备19023445号-2号
友情链接