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模擬第三方項目)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM