Android 中能夠作為 Log 開關的一些操作以及安全性淺談

image.png

自定義常量


開發階段利用 Log 日志方便代碼調試是再常見不過的事情。出于安全考慮,這種做法僅限于 Debug 模式,Release 模式下打包發布時一定要關掉。所以在我們的項目中,一定會有一個工具類或者方法來控制 Log 日志的使用,比如:

public class LogUtils {
    
    public static final Boolean DEBUG_MODE = true;
    
    public static void d(String message) {
        if (DEBUG_MODE) {
            Log.d("TAG", message);       
        }
    }
    
}

常見的做法便是像上面這樣,自定義一個布爾類型的常量作為開關來控制是否打印日志。但是這種做法有一個弊端,那就是每次發布 Release 包時都需要手動修改這個常量的值為 false,然后下一次開發階段再手動修改為 true。

雖然是很簡單的手動修改操作,但是也很容易忘記。那么有沒有一種辦法實現自動化管理呢?答案當然是有的,使用 BuildConfig 類。

BuildConfig


類似 R 資源文件,BuildConfig 也是在編譯階段,Gradle 插件自動生成的一個 class 文件。該文件包含一些幫助開發人員辨別當前 build 類型的常量信息。當然你也可以通過 Gradle 提供的定制功能向該文件里面添加其他輔助內容。這里我們看一下默認情況下,BuildConfig 文件都包含有哪些內容:

public final class BuildConfig {
    public static final boolean DEBUG = Boolean.parseBoolean("true");
    public static final String APPLICATION_ID = "com.yifeng.sample";
    public static final String BUILD_TYPE = "debug";
    public static final String FLAVOR = "";
    public static final int VERSION_CODE = 1;
    public static final String VERSION_NAME = "1.0";
}

能夠看出,都是一些大家很熟悉的信息。其中包括一個 DEBUG 常量,其值便可用于判斷當前 build 類型。debug 模式下為 true,release 模式下為 false。所以,使用 BuildConfig.DEBUG 可以替代前面我們自定義的常量,實現自動管理 Log 日志的打印:

public static void d(String message) {
    if (BuildConfig.DEBUG) {
        Log.d("TAG", message);
    }
}

看上去貌似已經很完美了,但其實還是有瑕疵的。BuildConfig 類文件的生成依據于 Module,也就是說每一個 Module 編譯時都會產生自己的這個文件。如果你的主 app module 使用其他依賴 module 中 BuildConfig 文件里面的 DEBUG 值,就需要多加注意。

默認情況下,Library 的構建永遠是以 Release 模式執行的,所以其 BuildConfig.DEBUG 值一定是 false!即使主 Module 使用 Debug 模式構建,也是如此。

那么,有沒有辦法修改 Library Module 的默認構建方式呢?答案也是肯定的。打開對應 Library 的 build.gradle 文件,添加這樣一行配置代碼:

android {
    // 這里省略其他內容
    publishNonDefault true
}

即表示不使用默認構建方式,編譯時也會自動生成其他 build 類型的 BuildConfig 類文件。你可以在相應 Library 路徑下查看配置該命令前后 BuildConfig 文件的生成情況,目錄地址為:

libraryName/build/generated/source/buildConfig/ + debug/release

然后在我們的主 Module 依賴的時候同時引入 debug 和 release 兩種配置,這里以 extras/PullToRefresh 作為 Library 為例,看下依賴代碼:

dependencies {
    releaseCompile project(path: ':extras:PullToRefresh', configuration: 'release')
    debugCompile project(path: ':extras:PullToRefresh', configuration: 'debug')
}

如此這般,便可以解決前面提到的依賴 Module 問題。當然,如果你的項目比較簡單,只是單一 Module,也就不存在這個問題。

但是如果項目中的依賴 Module 比較多的話,這種處理方式還是略顯麻煩。你需要在用到的地方針對每個 Module 逐一處理。其實還有一種更好的解決方案,那就是使用 Manifest 清單文件中 application 標簽里的 debuggable 屬性。

ApplicationInfo


application 標簽里有個 android:debuggable 屬性,表示當前應用是否可以被調試(一般不建議手動設置這個屬性)。這個屬性也會隨著 build 類型自動改變。所以,利用這個特性也能判定應用是否處于 Debug 模式,比如:

public static boolean isDebug(Context context) {
    return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}

控制 Log 日志打印的開關,除了上面講到的這些方式,其實還有別的方式。比如利用 Gradle 的靈活性在 build.gradle 文件中自定義一個 Boolean 變量,根據 build 類型動態賦值,也能達到我們的目的。

更安全的 Log 用法


前面所有這些做法都只是使 release 包不去顯示 Log 日志,從而提高安全性。但是,有沒有想過,如果 apk 被反編譯的話,這些 Log 相關的代碼還是能夠別識別出來,別人只需要稍作修改,重新打包,依舊能夠使 Log 重現。

當然,使用常量作為 LogUtils 中的判斷條件的話,根據 proguard 的優化規則,在 Release 包中是不包含條件體中的 Log.d 等操作代碼的。關于這一點,可以自己反編譯 apk 嘗試看下。

然而,在其他調用 LogUtils 工具類的地方依舊暴露了我們的意圖。所以,定義一個 LogUtils 類雖然提高了使用 Log 的效率,依舊解決不了 Log 安全的問題。相比而言,我們做了這么多努力只是稍微提高了一些安全的門檻而已。

所以,最好的辦法就是,Release 包中不包含任何用于調試的 Log 代碼(如果使用 LogUtils 的話,也包括 該類的調用)。也就是說,不使用 LogUtils 工具類封裝,在任何需要的地方,不嫌麻煩的逐一添加判斷條件:(可以使用 Live Template 提高效率)

if (BuildConfig.DEBUG) {
    Log.d("TAG", message);       
}

這樣,打包時,開啟 proguard 后,Release 包會自動刪除上面的代碼,徹底根絕 Log 引發的安全問題。關于這一部分的細節操作,可以參考這兩篇文章:

(END)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,836評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,807評論 25 708
  • 這一章主要針對項目中可以用到的一些實用功能來介紹Android Gradle,比如如何隱藏我們的證書文件,降低風險...
    acc8226閱讀 7,665評論 3 25
  • 我想擁有一個本領,但我卻一直在練習和它相反的事情。 一天的學習,家庭,健康等等宣言就在有條不紊的進行。晚上的錦囊會...
    水沁年華閱讀 234評論 0 0
  • 當你覺得當下不順,生活混亂,那便是忘卻不堪重新開始的時候了。能渡人便也能渡自己。 待花開,
    左手三通閱讀 167評論 0 0