Android系統資訊和安全機制
導語
在android的世界了,不同的軟體,硬體資訊就像一個國家的經濟水平,軍事水平,不同的配置引數,代表著一個android帝國的強弱,所以廠商喜歡打配置戰。
主要內容
- Android系統資訊的獲取
- PackageManager的使用
- ActivityManager的使用
- 解析Packages.xml獲取系統資訊
- Android安全機制
具體內容
Android系統資訊的獲取
由於android手機的開源性,手機的配置各種各樣,那些優化大師之類的東西,都可以跑分和看配置資訊,那他們是從哪裡知道這些資訊的呢?遙想獲取系統的配置資訊,通常可以從以下兩個方面獲取:
- android.os.Build
- SystemProperty
android.os.Build
android.os.Build類裡面的資訊非常的豐富,它包含了系統編譯時的大量裝置,配置資訊,我們列舉一點:
- Build.BOARD——主機板
- Build.BRAND——Android系統定製商
- Build.SUPPORTED_ABIS——CPU指令集
- Build.DEVICE——裝置引數
- Build.DISPLAY——顯示屏引數
- Build.FINGERPRINT——唯一編號
- Build.SERIAL——硬體序列號
- Build.ID——修訂版本列表
- Build.MANUFACTURER——硬體製造商
- Build.MODEL——版本
- Build.HARDWARE——硬體名
- Build.PRODUCT——手機產品名
- Build.TAGS——描述Build的標籤
- Build.TYPE——Builder型別
- Build.VERSION.CODENAME——當前開發代號
- Build.VERSION.INCREMENTAL——原始碼控制版本號
- Build.VERSION.RELEASE——版本字串
- Build.VERSION.SDK_INT——版本號
- Build.HOST——host值
- Build.USER——User名
- Build.TIME——編譯時間
上面的一些引數沒有註釋,他們來自系統的RO值中,這些值都是手機生產商配置的只讀的引數值,根據廠家的配置不同而不同,接下來我們再來看一下另一個儲存裝置軟硬體資訊的類——SystemProperty。
SystemProperty
SystemProperty類包含了許多系統配置屬性值和引數,很多資訊和上面通過android.os.Build獲取的值是相同的,我們列舉一些常用的:
- os.version——OS版本
- os.name——OS名稱
- os.arch——OS架構
- user.home——home屬性
- user.name——name屬性
- user.dir——Dir屬性
- user.timezone——時區
- path.separator——路徑分隔符
- line.separator——行分隔符
- file.separator——檔案分隔符
- java.vendor.url——Java vender Url屬性
- java.class.path——Java Class屬性
- java.class.version——Java Class版本
- java.vendor——Java Vender屬性
- java.version——Java版本
- java.home——Java Home屬性
Android系統資訊例項
下面我們用一個簡單的例項來了解一下把。
通過android.os.Build這個類,我們可以直接獲取到Build提供的系統資訊,而通過System.getProperty(“xxx”),我們可以訪問到系統的屬性。
在例項中獲取到的資訊與上述的基本一致,執行如圖。
tv_message.append("主機板:"+ Build.BOARD+"\n");
tv_message.append("Android系統定製商:"+ Build.BRAND+"\n");
tv_message.append("CPU指令集:"+ Build.SUPPORTED_ABIS+"\n");
tv_message.append("設定引數:"+ Build.DEVICE+"\n");
tv_message.append("顯示屏引數:"+ Build.DISPLAY+"\n");
tv_message.append("唯一編號:"+ Build.SERIAL+"\n");
用System.getProperty。
tv.append("OS版本:"+System.getProperty("os.version")+"\n");
tv.append("OS名稱:"+System.getProperty("os.name")+"\n");
tv.append("OS架構:"+System.getProperty("os.arch")+"\n");
tv.append("Home屬性:"+System.getProperty("user.home")+"\n");
tv.append("Name屬性:"+System.getProperty("user.name")+"\n");
程式碼貼上一點就可以了
執行的例項程式中我們可以看到,我們已經獲取到了相當多的系統資訊,那麼這些資訊的來源又是哪兒呢?記得我們分析android系統目錄的時候提到過,在system/build.prop中,包含了很多的RO值,開啟命令窗,通過cat build.prop可以看到。
這裡我們可以看到很多前面通過android.os.Build所獲取到的系統資訊,同時,在adb shell中,還可以通過getprop來獲取對應的值。
除了上述的兩個方法,android系統還在另外一個非常重要的目錄來儲存系統資訊——/proc目錄,在adb shell中進入/proc目錄,通過ll命令檢視檔案資訊。
看了這麼多系統資訊,應該看Apk應用資訊了,在ADB Shell命令中,有兩個非常強大的助手,PM和AM,PM主宰著應用的包管理,而AM主宰著應用的活動管理。
PackageManager——APK應用程式資訊獲取值
我們看一張圖:
最裡面的框就代表整個Activity的資訊,系統提供了ActivityInfo類來進行封裝。
而Android提供了PackageManager來負責管理所有已安裝的App,PackageManager可以獲得AndroidManifest中不同節點的封裝資訊,下面是一些常用的封裝資訊:
ActivityInfo
ActivityInfo封裝在了Mainfest檔案中的< activity >和< eceiver>之間的所有資訊,包括name、icon、label、launchMode等。
ServiceInfo
ServiceInfo與ActivityInfo類似,封裝了< service>之間的所有資訊。
ApplicationInfo
它封裝了< application>之間的資訊,特別的是,ApplicationInfo包含了很多Flag,FLAG_SYSTEM表示為系統應用,FLAG_EXTERNAL_STORAGE表示為安裝在SDcard上的應用,通過這些flag可以很方便的判斷應用的型別。
PackageInfo
PackageInfo包含了所有的Activity和Service資訊。
ResolveInfo
ResolveInfo包含了< intent>資訊的上級資訊,所以它可以返回ActivityInfo、ServiceInfo等包含了< intent>的資訊,經常用來幫助找到那些包含特定intent條件的資訊,如帶分享功能、播放功能的應用。
有了這些封裝的資訊後,還需要有特定的方法來獲取它們,下面就是PackageManager中封裝的用來獲取這些資訊的方法:
- getPackageManager():通過這個方法可以返回一個PackageManager物件。
- getApplicationInfo():以ApplicationInfo的形式返回指定包名的ApplicationInfo。
- getApplicationIcon():返回指定包名的Icon。
- getInstalledApplications():以ApplicationInfo的形式返回安裝的應用。
- getInstalledPackages():以PackageInfo的形式返回安裝的應用。
- queryIntentActivities():返回指定Intent的ResolveInfo物件、Activity集合。
- queryIntentServices():返回指定Intent的ResolveInfo物件、Service集合。
- resolveActivity():返回指定Intent的Activity。
- resolveService():返回指定Intent的Service。
根據ApplicationInfo的flag來判斷App的型別:
- 如果當前應用的flags & ApplicationInfo.FLAG_SYSTEM != 0則為系統應用。
- 如果flags & ApplicationInfo.FLAG_SYSTEM <= 0 則為第三方應用。
- 特殊的當系統應用升級後也會成為第三方應用,此時 flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0。
- 如果flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0 則為安裝在SDCard上的應用。
我們通過一個例項來分析。
我們封裝一個Bean來儲存我們所需的欄位:
package com.lgl.systemmesage;
import android.graphics.drawable.Drawable;
/**
* Bean
* Created by LGL on 2016/4/28.
*/
public class PMAPPInfo {
//應用名
private String appLabel;
//圖示
private Drawable appIcon;
//包名
private String pkgName;
//構造方法
public PMAPPInfo(){
}
public String getAppLabel() {
return appLabel;
}
public void setAppLabel(String appLabel) {
this.appLabel = appLabel;
}
public Drawable getAppIcon() {
return appIcon;
}
public void setAppIcon(Drawable appIcon) {
this.appIcon = appIcon;
}
public String getPkgName() {
return pkgName;
}
public void setPkgName(String pkgName) {
this.pkgName = pkgName;
}
}
接下來,我們通過上面的方法判斷各種型別的應用,我們的主佈局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="All APP"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_other"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Other App"
android:textAllCaps="false" />
<Button
android:id="@+id/btn_system"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="System App"
android:textAllCaps="false" />
<ListView
android:id="@+id/mListView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></ListView>
</LinearLayout>
這裡有一個listview,所以我們需要一個adapter和一個item:
package com.lgl.systemmesage;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* 資料來源
* Created by LGL on 2016/4/28.
*/
public class PkgAdapter extends BaseAdapter {
private Context mContext;
private List<PMAPPInfo> mList;
public PkgAdapter(Context context) {
mContext = context;
mList = new ArrayList<>();
}
public void addAll(List<PMAPPInfo> list) {
mList.clear();
mList.addAll(list);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public PMAPPInfo getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
PMAPPInfo item = getItem(position);
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false);
holder.mIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
holder.mLabel = (TextView) convertView.findViewById(R.id.tv_label);
holder.mPkgName = (TextView) convertView.findViewById(R.id.tv_pkg_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.mIcon.setImageDrawable(item.getAppIcon());
holder.mLabel.setText(item.getAppLabel());
holder.mPkgName.setText(item.getPkgName());
return convertView;
}
static class ViewHolder {
ImageView mIcon;
TextView mLabel;
TextView mPkgName;
}
}
item就簡單了:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_pkg_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
那我們主程式的邏輯就是:
package com.lgl.systemmesage;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
/**
* 軟體列表
* Created by LGL on 2016/4/28.
*/
public class APP extends AppCompatActivity implements View.OnClickListener{
private PackageManager mPackageManager;
private ListView mListView;
private PkgAdapter mAdapter;
List<PMAPPInfo> result;
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app);
mPackageManager = getPackageManager();
mListView = (ListView) findViewById(R.id.mListView);
mAdapter = new PkgAdapter(this);
mListView.setEmptyView(findViewById(R.id.empty));
mListView.setAdapter(mAdapter);
findViewById(R.id.btn_all).setOnClickListener(this);
findViewById(R.id.btn_other).setOnClickListener(this);
findViewById(R.id.btn_system).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_all:
result = getAppInfo(R.id.btn_all);
break;
case R.id.btn_other:
result = getAppInfo(R.id.btn_other);
break;
case R.id.btn_system:
result = getAppInfo(R.id.btn_system);
break;
default:
result = new ArrayList<>();
}
mAdapter.addAll(result);
}
private List<PMAPPInfo> getAppInfo(int flag) {
List<ApplicationInfo> appInfos = mPackageManager.getInstalledApplications(
PackageManager.GET_UNINSTALLED_PACKAGES);
List<PMAPPInfo> list = new ArrayList<>();
//根據不同的flag來切換顯示不同的App型別
switch (flag) {
case R.id.btn_all:
list.clear();
for (ApplicationInfo appInfo : appInfos) {
list.add(makeAppInfo(appInfo));
}
break;
case R.id.btn_other:
list.clear();
for (ApplicationInfo appInfo : appInfos) {
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
list.add(makeAppInfo(appInfo));
} else if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0){
list.add(makeAppInfo(appInfo));
}
}
break;
case R.id.btn_system:
list.clear();
for (ApplicationInfo appInfo : appInfos) {
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
list.add(makeAppInfo(appInfo));
}
}
break;
}
return list;
}
private PMAPPInfo makeAppInfo(ApplicationInfo appInfo) {
PMAPPInfo info = new PMAPPInfo();
info.setAppIcon(appInfo.loadIcon(mPackageManager));
info.setAppLabel(appInfo.loadLabel(mPackageManager).toString());
info.setPkgName(appInfo.packageName);
return info;
}
}
效果圖:
ActivityManager——Apk應用資訊獲取
前面所使用的packagemanager獲取的是所有的應用包名,但是哼哈二將還有一名大獎沒有說道,那就是ActivityManager了,他的功能四號不遜色前者,事實上,他在使用上各有側重點,前者側重於獲取應用的包資訊,後者獲取執行的應用程式資訊。
同packagemanager一樣,ActivityManager也封裝了不少的Bean物件,我們選幾個重點來說一下:
- ActivityManager.MemoryInfo——MemoryInfo有幾個非常重要的欄位:availMem(系統可用記憶體),totalMem(總記憶體),threshold(低記憶體的閾值,即區分是否低記憶體的臨界值),lowMemory(是否處於低記憶體)。
- Debug.MemoryInfo——這個MemoryInfo用於統計程序下的記憶體資訊。
- RunningAppProcessInfo——執行程序的資訊,儲存的欄位有:processName(程序名),pid(程序pid),uid(程序uid),pkgList(該程序下的所有包)
- RunningServiceInfo——執行的服務資訊,在它裡面同樣包含了一些服務程序資訊,同時還有一些其他資訊。activeSince(第一次被啟用的時間、方式),foreground(服務是否在後臺執行)。
我們同樣的用一個例項來講解:
package com.lgl.systemmesage;
/**
* Created by LGL on 2016/4/28.
*/
public class AMProcessInfo {
private String pid;
private String uid;
private String memorySize;
private String processName;
public AMProcessInfo(){
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getProcessName() {
return processName;
}
public void setProcessName(String processName) {
this.processName = processName;
}
public String getMemorySize() {
return memorySize;
}
public void setMemorySize(String memorySize) {
this.memorySize = memorySize;
}
}
然後我們用一個方法就可以獲取到了:
/**
* 正在執行
* @return
*/
private List<ActivityManager.RunningAppProcessInfo> getRunningProcossInfo(){
mAMProcessInfo = new ArrayList<>();
List<ActivityManager.RunningAppProcessInfo>appRunningList = activityManager.getRunningAppProcesses();
for (int i = 0;i<appRunningList.size();i++){
ActivityManager.RunningAppProcessInfo info = appRunningList.get(i);
int pid = info.pid;
int uid = info.uid;
String procossName = info.processName;
int[]memoryPid = new int[]{pid};
Debug.MemoryInfo[] memoryInfos = activityManager.getProcessMemoryInfo(memoryPid);
int memorySize = memoryInfos[0].getTotalPss();
AMProcessInfo processInfo = new AMProcessInfo();
processInfo.setPid(""+pid);
processInfo.setUid(""+uid);
processInfo.setMemorySize(""+memorySize);
processInfo.setProcessName(procossName);
appRunningList.add(processInfo);
}
return appRunningList;
}
效果圖:
解析Packages.xml獲取系統資訊
熟悉Android開機啟動流程的朋友大概知道,在系統初始化到時候,packagemanager的底層實現類packagemanagerService會去掃描系統的一些特定目錄,並且解析其中的Apk檔案,同時Android把他獲取到的應用資訊儲存到xml中,做成一個應用的花名冊,就是data/system/apckages.xml,我們用adb pull命令把他匯出來,裡面的資訊也太多了,但是我們只要知道結果根節點就可以了。
標籤
permissions標籤定義了現在系統所有的許可權,也分兩類,系統定義的和app定義的。
標籤
package代表的是一個apk的屬性。其中各節點的資訊含義大致為:
- name:APK的包名
- cadePath:APK安裝路徑,主要在system/app和data/app兩種,前者放系統級別的,後者放系統安裝的
- userid:使用者ID
- version:版本
標籤
對應apk的清單檔案,記錄apk的許可權資訊。
通過這個xml檔案的標籤,可以獲取到很多手機應用的資訊,通常在進行系統層開發的時候,可以通過這個xml獲取更多有意義的東西。
Android安全機制
道高一尺魔高一丈,自古以來就沒有什麼絕對的安全,所以Google也建立起了一層層的壁壘,保護Android的核心安全,我們來詳細瞭解一下。
Android安全機制介紹
第一道防線
程式碼安全機制——程式碼混淆proguard。
由於java語言的特殊性,即使是編譯成apk的應用程式也存在反編譯的風險,而proguard則是在程式碼從上對app的第一道程式,他混淆關鍵程式碼,替換命名,讓破壞者閱讀難,同樣也可以壓縮程式碼,優化編譯後的位元組。第二道防線
應用接入許可權控制——清單檔案許可權宣告,許可權檢查機制。
任何app在使用Android受限資源的時候,都需要顯示向系統生命許可權,只有當一個應用app具有相應的許可權,才能申請相應的資源,通過許可權機制的檢查並且使用並且使用系統的Binder物件完成對系統服務的呼叫,但是這道防線也有先天的不足,如以下幾項:- 被授予的許可權無法停止。
- 在應用宣告app使用許可權的時候,使用者無法針對部分許可權進行限制。
- 許可權的判斷機制與使用者的安全理念相關。
Android系統通常按照以下順序來檢查操作者的許可權:
- 首先,判斷permission名稱.如果為空則直接返回PERMISSION_DENIED
- 其次。判斷Uid,如果為0則為root許可權,不做許可權控制,如果為systyemsystem service的uid則為系統服務.不做許可權控制:如果Uid與引數中的請求uid不同則返回PERMISSION_DENIED 。
- 最後,通過呼叫packagemanageservice.checkUidPermission()方法來判斷該uid是否具有相應的許可權,該方法會去xml的許可權列表和系統級的許可權進行查詢 。
通過上面的步驟Android就確定了使用者是否具有某項使用許可權。
第三道防線
應用簽名機制一數字證書。
Android中所有的app都會有個數字證書,這就是app的簽名.數字證書用於保護app的作者和其app的信任關係,只有擁有相同數字簽名的app,才會在升級時被認為是同一app,而且Android系統不會安裝沒有簽名的App。第四道防線
Linux核心層安全機制一一Uid 訪問許可權控制。
Animid本質是基於Linux核心開發的,所以Android同樣繼承了Linux的安全特性,比如Linux檔案系統的許可權控制是由user,group,other與讀,寫,執行的不同組合來實現的,同樣,Android也實現了這套機制”通常情況下.只有system,root使用者才有許可權訪問到系統檔案,而一般使用者無法訪問。第五道防線
Android虛擬機器沙箱機制——沙箱隔流。
Android的App執行在虛擬機器中 因此才有沙箱機制,可以讓應用之間相互隔離,通常情況下,不同的應用之間不能互相訪問。每個App都單獨的執行在虛似機中,與其他應用完全隔離.在實現安全機制的基礎上,也讓應用之間能夠互不影響,即時一個應用崩潰,也不會導致其他應用異常。
雖然通過以上的五道防線,仍然不能完全保證Android的核心安全,但卻可以在最大程度上給破壞者增加難度,從另一方面來說,這些破壞者的破解也真是推動Android安全機制逐漸健全的動力。
Android系統安全隱患
雖說Android建立起來了N道防線,但是沒有絕對的安全所以在Android中也有一些破解之法。
程式碼漏洞
這個問題存在世界上所有的程式中,沒有誰敢保證自己的程式沒有bug,有漏洞,如果遇到這種問題,大家只能儘快的升級版本,更新補丁,才能杜絕利用漏洞的攻擊裝,比如Android的LaunchAnyWhere,FakeId,這些都是bug,就是在編寫的時候產生的漏洞,只有期待官方的更新了。
root風險
Root許可權是指Android的系統管理員許可權,類似於windows系統中的Administrator。具有Root許可權的使用者可以訪問和修改手機中幾乎所有的檔案,“Root”在一段時間內一度成為Android的代名詞,無Root,不Android”。的確,,Root掉手機後,可以解鎖很多普通使用者無法完成的工作,如限制各個應用app的資料流量。系統檔案管理,自定義修改系統等,但同時手機的安全性也會因此大打折扣。隨著android系統越來越完善,root的必要性也越來越低普通使用者在不root的情況下,完全可以正常使用大部分App。需要Root許可權的大多為一些開發者,由於開發的需要,,將手機root,而root後的手機,就少了一層Linux的天然屏障,整個系統核心就完全暴露在人侵者面前,在你沒有察覺的情況下大肆破壞。所以,針對普通使用者,希望都儘量不要Root手機以免帶來不必要的損失。
安全機制不健全
由於Android的許可權管理機制並不完美,所以很多手機開發商,通常會在Rom中增加自己的一套許可權管理工具來幫助使用者控制手機中應用的許可權,如應用許可。
使用者安全意識
使用者對於安全隱患的察覺裡也是保護手機安全的一個重要因素。使用者可以通過在正規的應用市場下載和安裝應用時通過列出來的應用許可權申請資訊來大致判斷一個應用的安全性,比如我們曾經十分喜歡用的“xx神器”,其實沒有一點技術含量,無非就是在你安裝了應用之後遍歷一遍你的聯絡人併發送帶有連結的簡訊而已當用戶在安裝不明來源的應用時如果一個娛樂型別的app生命許可權的時候不僅要聯絡人又要簡訊許可權,這個時候就需要警惕了,使用者也可以在市場上下載一些安全類App,如LEB安全大師,360安全等, 雖然這些軟體會加重系統負擔,但是為了安全也是值得的。
Android開發原則與安全
眾所周知,Android與ios系統一個非常顯著的區別就是,一個是開放系統,一個是封閉系統,開放自然有開放的好處,技術進步快,產品豐富,封閉也有封閉的好處,安全性高,可控性高,Google本著開源的精神開放了Android的原始碼,但隨之而來的各種安全問題也讓Android倍受詬病,過度的開放與可定製化,不僅造成了Android的碎片化嚴重,同時也給很多不法應用以可乘之機,但可喜的是,隨著Android的發展日益壯大,Google也在著手處理開發與安全的問題,相信在不久的將來,這一矛盾會越來越小。
Android Apk反編譯
使用三個工具:
- apktool:反編譯apk的xml檔案。
- Dex2jar:classes.dex轉為jar檔案。
- jd-gui:檢視jar檔案。
Android APK 加密
由於java位元組的特殊性,他很容易反編譯,為了能夠保護好程式碼,我們通常會使用一些措施,比如說混淆,而在Android studio中,可以很方便的使用ProGuard,在Gradle Scripts目錄下。
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
這裡的minifyEnabled屬性就是控制是否啟動ProGuard,這個屬性以前叫做runProgyard,在Android studio1.1的時候改成minifyEnabled,將他設定成true,就可以混淆了,他位於《SDK目錄下的tools/proguard/proguard-android.txt目錄下,大部分的情況下使用使用這個預設的混淆就好了,後面亦不過分是專案中自定義的混淆,可以在專案的app資料夾下找到這個檔案,在這根檔案裡可以定義引用的第三方依賴庫和混淆規則,配置好ProGuard之後,用AS到處apk即可。
總結
學會獲取系統資訊。