• Gradle混淆+打包Jar包基础


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

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

    通常我们编写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模拟第三方项目)。

  • 相关阅读:
    jQuery cxCalendar 日期选择器
    JS中this的4种绑定规则
    Redis入门教程
    大型网站限流算法的实现和改造
    JS中的继承(下)
    剑指Offer面试题:6.旋转数组中的最小数字
    剑指Offer面试题:5.重建二叉树
    剑指Offer面试题:4.从尾到头打印链表
    C++之运算符重载
    剑指Offer面试题:3.替换空格
  • 原文地址:https://www.cnblogs.com/xiaoshubao/p/5599073.html
Copyright © 2020-2023  润新知