1. 程式人生 > >阿里Android開發手冊正式版一覽

阿里Android開發手冊正式版一覽

  新年伊始,春意盎然之際,阿里巴巴在2月28日再度為工程師們送上了一份重磅開春好禮:《阿里巴巴Android開發手冊》。

    該手冊長達66頁,是阿里巴巴集團各大 Android 開發團隊的集體智慧結晶和經驗總結,將淘寶、天貓、閒魚、釘釘等 App 長期開發迭代和優化經驗系統地整理成冊, 以指導 Android 開發者更加高效、高質量地進行 App 開發,呈現給使用者體驗好、效能優、穩定性佳、安全性高的產品。

    本手冊以開發者為中心視角分為 Java語言規範(遵循《阿里巴巴 Java開發手冊》),Android 資原始檔命名與使用,Android 基本元件,UI 與佈局,程序、執行緒與訊息通訊,檔案與資料庫,Bitmap、 Drawable 與動畫,安全,其他等九大部分,根據約束力強弱,規約依次分為強制、推薦、參考三大類:

【強制】 必須遵守,違反本約定或將會引起嚴重的後果;

【推薦】 儘量遵守,長期遵守有助於系統穩定性和合作效率的提升;

【參考】 充分理解,技術意識的引導,是個人學習、團隊溝通、專案合作的方向。

    以下為該手冊的詳細內容:

一、Java語言規範

遵循《阿里巴巴 Java 開發手冊》,如果有需要可以關注分享達人秀公眾號回覆“Java開發手冊”獲取最新紀念版下載連結。

二、Android資原始檔命名與使用

1.【推薦】資原始檔需帶模組字首。

2.【推薦】layout 檔案的命名方式。

    Activity 的 layout 以 module_activity 開頭

    Fragment 的 layout 以 module_fragment 開頭

    Dialog 的 layout 以 module_dialog 開頭

    include 的 layout 以 module_include 開頭

    ListView 的行 layout 以 module_list_item 開頭

    RecyclerView 的 item layout 以 module_recycle_item 開頭

    GridView 的行 layout 以 module_grid_item 開頭

3.【推薦】drawable 資源名稱以小寫單詞+下劃線的方式命名,根據解析度不同存放在不同的 drawable 目錄下,建議只使用一套,例如 drawable-xhdpi。採用規則如下:

模組名_業務功能描述_控制元件描述_控制元件狀態限定詞

    如:module_login_btn_pressed,module_tabs_icon_home_normal

4.【推薦】anim 資源名稱以小寫單詞+下劃線的方式命名,採用以下規則:

模組名_邏輯名稱_[方向|序號]

tween 動 畫 資 源 : 盡 可 能 以 通 用 的 動 畫 名 稱 命 名 , 如:module_fade_in ,module_fade_out , module_push_down_in (動畫+方向);

frame 動畫資源:儘可能以模 塊+功能命名+序號。如:module_loading_grey_001

5.【推薦】color 資源使用#AARRGGBB 格式,寫入 module_colors.xml 檔案中,命名格式採用以下規則:

模組名_邏輯名稱_顏色

    如:#33b5e5e5

6.【推薦】dimen 資源以小寫單詞+下劃線方式命名,寫入 module_dimens.xml 檔案中,採用以下規則:

模組名_描述資訊

    如:1dp

7.【推薦】style 資源採用小寫單詞+下劃線方式命名,寫入 module_styles.xml 檔案中,採用以下規則:

父 style 名稱.當前 style 名稱

8.【推薦】string資原始檔或者文字用到字元需要全部寫入 module_strings.xml檔案中,字串以小寫單詞+下劃線的方式命名,採用以下規則:

 模組名_邏輯名稱

    如:moudule_login_tips,module_homepage_notice_desc

9.【推薦】Id 資源原則上以駝峰法命名,View 元件的資源 id 需要以 View 的縮寫作為字首。常用縮寫表如下:

    其它控制元件的縮寫推薦使用小寫字母並用下劃線進行分割,例如:

ProgressBar 對應的縮寫為 progress_bar

DatePicker 對應的縮寫為 date_picker

10.【推薦】大解析度圖片(單維度超過 1000)大解析度圖片建議統一放在 xxhdpi 目錄下管理,否則將導致佔用記憶體成倍數增加。

    說明:

    為了支援多種螢幕尺寸和密度, Android 為多種螢幕提供不同的資源目錄進行適配。為不同螢幕密度提供不同的點陣圖可繪製物件,可用於密度特定資源的配置限定符(在

下面詳述) 包括 ldpi(低)、 mdpi(中)、 hdpi(高)、 xhdpi(超高)、 xxhdpi (超超高)和 xxxhdpi(超超超高)。例如,高密度螢幕的點陣圖應使用 drawable-hdpi/。

    根據當前的裝置螢幕尺寸和密度,將會尋找最匹配的資源,如果將高解析度圖片放入低密度目錄,將會造成低端機載入過大圖片資源,又可能造成 OOM,同時也是資源浪費,沒有必要在低端機使用大圖。

三、Android基本元件

Android 基本元件指 Activity、 Fragment、 Service、 BroadcastReceiver、ContentProvider 等等。

1.【強制】Activity 間的資料通訊,對於資料量比較大的,避免使用 Intent + Parcelable的方式,可以考慮 EventBus 等替代方案,以免造成 TransactionTooLargeException。

2.【推薦】Activity#onSaveInstanceState()方法不是 Activity 生命週期方法,也不保證一定會被呼叫。它是用來在 Activity 被意外銷燬時儲存 UI 狀態的,只能用於儲存臨時性資料,例如 UI 控制元件的屬性等,不能跟資料的持久化儲存混為一談。持久化儲存應該在 Activity#onPause()/onStop()中實行。

3.【強制】Activity 間通過隱式 Intent 的跳轉,在發出 Intent 之前必須通過 resolveActivity檢查,避免找不到合適的呼叫元件,造成 ActivityNotFoundException 的異常。

4.【強制】避免在 Service#onStartCommand()/onBind()方法中執行耗時操作,如果確實有需求,應改用 IntentService 或採用其他非同步機制完成。

5.【強制】避免在 BroadcastReceiver#onReceive()中執行耗時操作,如果有耗時工作,應該建立 IntentService 完成,而不應該在 BroadcastReceiver 內建立子執行緒去做。

    說明:

    由於該方法是在主執行緒執行,如果執行耗時操作會導致 UI 不流暢。可以使用IntentService 、 創 建 HandlerThread 或 者 調 用 Context#registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法等方式,在其他 Wroker 執行緒執行 onReceive 方法。BroadcastReceiver#onReceive()方法耗時超過 10 秒鐘,可能會被系統殺死。

6.【強制】避免使用隱式 Intent 廣播敏感資訊,資訊可能被其他註冊了對應BroadcastReceiver 的 App 接收。

    說明:

    通過 Context#sendBroadcast()傳送的隱式廣播會被所有感興趣的 receiver 接收,惡意應用註冊監聽該廣播的 receiver 可能會獲取到 Intent 中傳遞的敏感資訊,並進行其他危險操作。如果傳送的廣播為使用 Context#sendOrderedBroadcast()方法傳送的有序廣播,優先順序較高的惡意 receiver 可能直接丟棄該廣播,造成服務不可用,或者向廣播結果塞入惡意資料。

    如果廣播僅限於應用內,則可以使用 LocalBroadcastManager#sendBroadcast()實現,避免敏感資訊外洩和 Intent 攔截的風險。

7.【推薦】添 加 Fragment 時 , 確 保 FragmentTransaction#commit() 在Activity#onPostResume()或者 FragmentActivity#onResumeFragments()內呼叫。不要隨意使用 FragmentTransaction#commitAllowingStateLoss()來代替,任何commitAllowingStateLoss()的使用必須經過 code review,確保無負面影響。

    說明:

    Activity 可 能 因 為 各 種 原 因 被 銷 毀 , Android 支 持 頁 面 被 銷 毀 前 通 過Activity#onSaveInstanceState() 保 存 自 己 的 狀 態 。 但 如 果FragmentTransaction.commit()發生在 Activity 狀態儲存之後,就會導致 Activity 重建、恢復狀態時無法還原頁面狀態,從而可能出錯。為了避免給使用者造成不好的體驗,系統會丟擲 IllegalStateExceptionStateLoss 異常。推薦的做法是在 Activity 的onPostResume() 或 onResumeFragments() ( 對 FragmentActivity ) 裡 執 行FragmentTransaction.commit(),如有必要也可在 onCreate()裡執行。不要隨意改用FragmentTransaction.commitAllowingStateLoss() 或 者 直 接 使 用 try-catch 避 免crash,這不是問題的根本解決之道,當且僅當你確認 Activity 重建、恢復狀態時,本次 commit 丟失不會造成影響時才可這麼做。

8.【推薦】不要在 Activity#onDestroy()內執行釋放資源的工作,例如一些工作執行緒的銷燬和停止,因為 onDestroy()執行的時機可能較晚。可根據實際需要,在Activity#onPause()/onStop()中結合 isFinishing()的判斷來執行。

9.【推薦】如非必須,避免使用巢狀的 Fragment。

    說明:

    巢狀 Fragment 是在 Android API 17 新增到 SDK 以及 Support 庫中的功能,Fragment 巢狀使用會有一些坑,容易出現 bug,比較常見的問題有如下幾種:

    1) onActivityResult()方法的處理錯亂,內嵌的 Fragment 可能收不到該方法的回撥,需要由宿主 Fragment 進行轉發處理;

    2) 突變動畫效果;

    3) 被繼承的 setRetainInstance(),導致在 Fragment 重建時多次觸發不必要的邏輯。

    非必須的場景儘可能避免使用巢狀 Fragment,如需使用請注意上述問題。

10.【推薦】總是使用顯式 Intent 啟動或者繫結 Service,且不要為服務宣告 Intent Filter,保證應用的安全性。如果確實需要使用隱式呼叫,則可為 Service 提供 Intent Filter並從 Intent 中排除相應的元件名稱,但必須搭配使用 Intent#setPackage()方法設定Intent 的指定包名,這樣可以充分消除目標服務的不確定性。

11.【推薦】Service 需要以多執行緒來併發處理多個啟動請求,建議使用 IntentService,可避免各種複雜的設定。

    說明:

    Service 元件一般執行主執行緒,應當避免耗時操作,如果有耗時操作應該在 Worker執行緒執行。 可以使用 IntentService 執行後臺任務。

12.【推薦】對於只用於應用內的廣播,優先使用 LocalBroadcastManager 來進行註冊和傳送,LocalBroadcastManager 安全性更好,同時擁有更高的執行效率。

    說明:

    對於使用 Context#sendBroadcast()等方法傳送全域性廣播的程式碼進行提示。如果該廣播僅用於應用內,則可以使用 LocalBroadcastManager 來避免廣播洩漏以及廣播被攔截等安全問題,同時相對全域性廣播本地廣播的更高效。

13.【推薦】當前 Activity的 onPause方法執行結束後才會執行下一個 Activity的 onCreate方法,所以在 onPause 方法中不適合做耗時較長的工作,這會影響到頁面之間的跳轉效率。

14.【強制】不要在 Android 的 Application 物件中快取資料。基礎元件之間的資料共享請使用 Intent 等機制,也可使用 SharedPreferences 等資料持久化機制。

15.【推薦】使用 Toast 時,建議定義一個全域性的 Toast 物件,這樣可以避免連續顯示Toast 時不能取消上一次 Toast 訊息的情況(如果你有連續彈出 Toast 的情況,避免使用 Toast.makeText)。

16.【強制】使用 Adapter 的時候,如果你使用了 ViewHolder 做快取,在 getView()的方法中無論這項 convertView 的每個子控制元件是否需要設定屬性(比如某個 TextView設定的文字可能為 null,某個按鈕的背景色為透明,某控制元件的顏色為透明等),都需要為其顯式設定屬性(Textview 的文字為空也需要設定 setText(""),背景透明也需要設定),否則在滑動的過程中,因為 adapter item 複用的原因,會出現內容的顯示錯亂。

17.【強制】Activity或者 Fragment 中動態註冊 BroadCastReceiver 時, registerReceiver()和 unregisterReceiver()要成對出現。

    說明:

    如果 registerReceiver()和 unregisterReceiver()不成對出現,則可能導致已經註冊的receiver 沒有在合適的時機登出,導致記憶體洩漏,佔用記憶體空間,加重 SystemService負擔。

    部分華為的機型會對 receiver 進行資源管控,單個應用註冊過多 receiver 會觸發管控模組丟擲異常,應用直接崩潰。

    Activity 的生命週期不對應,可能出現多次 onResume 造成 receiver 註冊多個,但最終只登出一個,其餘 receiver 產生記憶體洩漏。

四、UI與佈局

1.【強制】佈局中不得不使用 ViewGroup 多重巢狀時,不要使用 LinearLayout 巢狀,改用 RelativeLayout,可以有效降低巢狀數。

    說明:

    Android 應用頁面上任何一個 View 都需要經過 measure、 layout、 draw 三個步驟才能被正確的渲染。從 xml layout 的頂部節點開始進行 measure,每個子節點都需要向自己的父節點提供自己的尺寸來決定展示的位置,在此過程中可能還會重新measure(由此可能導致 measure 的時間消耗為原來的 2-3 倍)。節點所處位置越深,套嵌帶來的 measure 越多,計算就會越費時。這就是為什麼扁平的 View 結構會效能更好。

    同時,頁面擁上的 View 越多,measure、 layout、 draw 所花費的時間就越久。要縮短這個時間,關鍵是保持 View 的樹形結構儘量扁平,而且要移除所有不需要渲染的View。理想情況下,總共的 measure,layout,draw 時間應該被很好的控制在 16ms以內,以保證滑動螢幕時 UI 的流暢。

    要找到那些多餘的 View(增加渲染延遲的 view),可以用 Android Studio Monitor裡的 Hierarachy Viewer 工具,視覺化的檢視所有的 view。

2.【推薦】在 Activity 中顯示對話方塊或彈出浮層時,儘量使用 DialogFragment,而非Dialog/AlertDialog,這樣便於隨Activity生命週期管理對話方塊/彈出浮層的生命週期。

3.【推薦】原始檔統一採用 UTF-8 的形式進行編碼。

4.【強制】禁止在非 ui 執行緒進行 view 相關操作。

5.【推薦】文字大小使用單位 dp,view 大小使用單位 dp。對於 Textview,如果在文字大小確定的情況下推薦使用 wrap_content 佈局避免出現文字顯示不全的適配問題。

6.【強制】禁止在設計佈局時多次設定子 view 和父 view 中為同樣的背景造成頁面過度繪製,推薦將不需要顯示的佈局進行及時隱藏。

7.【推薦】靈活使用佈局,推薦 Merge、 ViewStub 來優化佈局,儘可能多的減少 UI佈局層級,推薦使用 FrameLayout,LinearLayout、 RelativeLayout 次之。

8.【推薦】在需要時刻重新整理某一區域的元件時,建議通過以下方式避免引發全域性 layout重新整理:

    1) 設定固定的 view 大小的高寬,如倒計時元件等;

    2) 呼叫 view 的 layout 方式修改位置,如彈幕元件等;

    3) 通過修改 canvas 位置並且呼叫 invalidate(int l, int t, int r, int b)等方式限定重新整理區域;

    4) 通過設定一個是否允許 requestLayout 的變數,然後重寫控制元件的 requestlayout、onSizeChanged 方 法 , 判 斷 控 件 的 大 小 沒 有 改 變 的 情 況 下 , 當 進 入requestLayout 的時候,直接返回而不呼叫 super 的 requestLayout 方法。

9.【推薦】不能在 Activity 沒有完全顯示時顯示 PopupWindow 和 Dialog。

10.【推薦】儘量不要使用 AnimationDrawable,它在初始化的時候就將所有圖片載入到記憶體中,特別佔記憶體,並且還不能釋放,釋放之後下次進入再次載入時會報錯。

    說明:

    Android 的幀動畫可以使用 AnimationDrawable 實現,但是如果你的幀動畫中如果包含過多幀圖片,一次性載入所有幀圖片所導致的記憶體消耗會使低端機發生 OOM異常。幀動畫所使用的圖片要注意降低記憶體消耗,當圖片比較大時,容易出現 OOM。

11.【強制】不能使用 ScrollView 包裹 ListView/GridView/ExpandableListVIew;因為這樣會把 ListView 的所有 Item 都載入到記憶體中,要消耗巨大的記憶體和 cpu 去繪製圖面。

    說明:

    ScrollView 中巢狀 List 或 RecyclerView 的做法官方明確禁止。除了開發過程中遇到的各種視覺和互動問題,這種做法對效能也有較大損耗。 ListView 等 UI 元件自身有垂直滾動功能,也沒有必要在巢狀一層 ScrollView。目前為了較好的 UI 體驗,更貼近 Material Design 的設計,推薦使用 NestedScrollView。

五、程序、執行緒與訊息通訊

1.【強制】不要通過 Intent 在 Android 基礎元件之間傳遞大資料(binder transaction快取為 1MB),可能導致 OOM。

2.【強制】在 Application 的業務初始化程式碼加入程序判斷,確保只在自己需要的程序初始化。特別是後臺程序減少不必要的業務初始化。

3.【強制】新建執行緒時,必須通過執行緒池提供(AsyncTask 或者 ThreadPoolExecutor或者其他形式自定義的執行緒池) ,不允許在應用中自行顯式建立執行緒。

    說明:

    使用執行緒池的好處是減少在建立和銷燬執行緒上所花的時間以及系統資源的開銷,解決資源不足的問題。如果不使用執行緒池,有可能造成系統建立大量同類執行緒而導致消耗完記憶體或者“過度切換”的問題。 另外建立匿名執行緒不便於後續的資源使用分析,對效能分析等會造成困擾。

4.【強制】執行緒池不允許使用 Executors 去建立,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確執行緒池的執行規則,規避資源耗盡的風險。

    說明:

    Executors 返回的執行緒池物件的弊端如下:

    1) FixedThreadPool 和 SingleThreadPool : 允 許 的 請 求 隊 列 長 度 為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM;

    2) CachedThreadPool 和 ScheduledThreadPool : 允 許 的 創 建 線 程 數 量 為Integer.MAX_VALUE,可能會建立大量的執行緒,從而導致 OOM。

5.【強制】子執行緒中不能更新介面,更新介面必須在主執行緒中進行,網路操作不能在主執行緒中呼叫。

6.【強制】不要在非 UI 執行緒中初始化 ViewStub,否則會返回 null。

7.【推薦】儘量減少不同 APP 之間的程序間通訊及拉起行為。拉起導致佔用系統資源,影響使用者體驗。

8.【推薦】新建執行緒時,定義能識別自己業務的執行緒名稱,便於效能優化和問題排查。

9.【推薦】ThreadPoolExecutor 設定執行緒存活時間(setKeepAliveTime),確保空閒時執行緒能被釋放。

10.【推薦】禁 止 在 多 進 程 之 間 用 SharedPreferences 共 享 數 據 , 雖 然 可 以(MODE_MULTI_PROCESS),但官方已不推薦。

11.【推薦】謹慎使用 Android 的多程序,多程序雖然能夠降低主程序的記憶體壓力,但會遇到如下問題:

    1) 不能實現完全退出所有 Activity 的功能;

    2) 首次進入新啟動程序的頁面時會有延時的現象(有可能黑屏、白屏幾秒,是白屏還是黑屏和新 Activity 的主題有關) ;

    3) 應用內多程序時,Application 例項化多次,需要考慮各個模組是否都需要在所有程序中初始化;

    4) 多程序間通過 SharedPreferences 共享資料時不穩定。

六、檔案與資料庫

1.【強制】任何時候不要硬編碼檔案路徑,請使用 Android 檔案系統 API 訪問。

    說明:

    Android 應用提供內部和外部儲存,分別用於存放應用自身資料以及應用產生的使用者資料。可以通過相關 API 介面獲取對應的目錄,進行檔案操作。

2.【強制】當使用外部儲存時,必須檢查外部儲存的可用性。

3.【強制】應用間共享檔案時,不要通過放寬檔案系統許可權的方式去實現,而應使用FileProvider。

4.【推薦】SharedPreference 中只能儲存簡單資料型別(int、 boolean、 String 等),複雜資料型別建議使用檔案、資料庫等其他方式儲存。

5.【推薦】SharedPreference 提 交 數 據 時 , 盡 量 使 用 Editor#apply() , 而 非Editor#commit()。一般來講,僅當需要確定提交結果,並據此有後續操作時,才使用 Editor#commit()。

    說明:

    SharedPreference 相關修改使用 apply 方法進行提交會先寫入記憶體,然後非同步寫入磁碟, commit 方法是直接寫入磁碟。如果頻繁操作的話 apply 的效能會優於 commit,apply 會將最後修改內容寫入磁碟。但是如果希望立刻獲取儲存操作的結果,並據此做相應的其他操作,應當使用 commit。

6.【強制】資料庫 Cursor 必須確保使用完後關閉,以免記憶體洩漏。

    說明:

    Cursor 是對資料庫查詢結果集管理的一個類,當查詢的結果集較小時,消耗記憶體不易察覺。但是當結果集較大,長時間重複操作會導致記憶體消耗過大,需要開發者在操作完成後手動關閉 Cursor。

    資料庫 Cursor 在建立及使用時,可能發生各種異常,無論程式是否正常結束,必須在最後確保 Cursor 正確關閉,以避免記憶體洩漏。同時,如果 Cursor 的使用還牽涉多執行緒場景,那麼需要自行保證操作同步。

7.【強制】多執行緒操作寫入資料庫時,需要使用事務,以免出現同步問題。

    說明:

    Android 的通過 SQLiteOpenHelper 獲取資料庫 SQLiteDatabase 例項, Helper 中會自動快取已經開啟的 SQLiteDatabase 例項,單個 App 中應使用 SQLiteOpenHelper的單例模式確保資料庫連線唯一。由於 SQLite 自身是資料庫級鎖,單個數據庫操作是保證執行緒安全的(不能同時寫入),transaction 時一次原子操作,因此處於事務中的操作是執行緒安全的。

    若同時開啟多個數據庫連線,並通過多執行緒寫入資料庫,會導致資料庫異常,提示資料庫已被鎖住。

8.【推薦】大資料寫入資料庫時,請使用事務或其他能夠提高 I/O 效率的機制,保證執行速度。

9.【強制】執行 SQL 語句時,應使用 SQLiteDatabase#insert()、 update()、 delete(),不要使用 SQLiteDatabase#execSQL(),以免 SQL 注入風險。

10.【強制】如果 ContentProvider 管理的資料儲存在 SQL 資料庫中,應該避免將不受信任的外部資料直接拼接在原始 SQL 語句中,可使用一個用於將 ? 作為可替換引數的選擇子句以及一個單獨的選擇引數陣列,會避免 SQL 注入。

七、Bitmap、Drawable與動畫

1.【強制】載入大圖片或者一次性載入多張圖片,應該在非同步執行緒中進行。圖片的載入,涉及到 IO 操作,以及 CPU 密集操作,很可能引起卡頓。

2.【強制】在 ListView,ViewPager,RecyclerView,GirdView 等元件中使用圖片時,應做好圖片的快取,避免始終持有圖片導致記憶體洩露,也避免重複建立圖片,引起性 能 問 題 。 建 議 使 用 Fresco ( https://github.com/facebook/fresco )、 Glide(https://github.com/bumptech/glide)等圖片庫。

3.【強制】png 圖片使用 tinypng 或者類似工具壓縮處理,減少包體積。

4.【推薦】應根據實際展示需要,壓縮圖片,而不是直接顯示原圖。手機螢幕比較小,直接顯示原圖,並不會增加視覺上的收益,但是卻會耗費大量寶貴的記憶體。

5.【強制】使用完畢的圖片,應該及時回收,釋放寶貴的記憶體。

6.【推薦】針對不同的螢幕密度,提供對應的圖片資源,使記憶體佔用和顯示效果達到合理的平衡。如果為了節省包體積,可以在不影響 UI 效果的前提下,省略低密度圖片。

7.【強制】在 Activity.onPause()或 Activity.onStop()回撥中,關閉當前 activity 正在執行的的動畫。

8.【推薦】在動畫或者其他非同步任務結束時,應該考慮回撥時刻的環境是否還支援業務處理。例如 Activity 的 onStop()函式已經執行,且在該函式中主動釋放了資源,此時回撥中如果不做判斷就會空指標崩潰。

9.【推薦】使用 inBitmap 重複利用記憶體空間,避免重複開闢新記憶體。

10.【推薦】使用 ARGB_565 代替 ARGB_888,在不怎麼降低視覺效果的前提下,減少記憶體佔用。

    說明:

    android.graphics.Bitmap.Config 類中關於圖片顏色的儲存方式定義:

    1) ALPHA_8 代表 8 位 Alpha 點陣圖;

    2) ARGB_4444 代表 16 位 ARGB 點陣圖;

    3) ARGB_8888 代表 32 位 ARGB 點陣圖;

    4) RGB_565 代表 8 位 RGB 點陣圖。

    點陣圖位數越高,儲存的顏色資訊越多,影象也就越逼真。大多數場景使用的是ARGB_8888 和 RGB_565,RGB_565 能夠在保證圖片質量的情況下大大減少記憶體的開銷,是解決 oom 的一種方法。

    但是一定要注意 RGB_565 是沒有透明度的,如果圖片本身需要保留透明度,那麼就不能使用 RGB_565。

11.【推薦】儘量減少 Bitmap (BitmapDrawable)的使用,儘量使用純色(ColorDrawable)、漸變色(GradientDrawable)、 StateSelector(StateListDrawable)等與 Shape 結合的形式構建繪圖。

12.【推薦】謹慎使用 gif 圖片,注意限制每個頁面允許同時播放的 gif 圖片,以及單個gif 圖片的大小。

13.【參考】大圖片資源不要直接打包到 apk,可以考慮通過檔案倉庫遠端下載,減小包體積。

14.【推薦】根據裝置效能,選擇性開啟複雜動畫,以實現一個整體較優的效能和體驗;

15.【推薦】在有強依賴 onAnimationEnd 回撥的互動時,如動畫播放完畢才能操作頁面 , onAnimationEnd 可 能 會 因 各 種 異 常 沒 被 回 調 ( 參 考 :https://stackoverflow.com/questions/5474923/onanimationend-is-not-getting-called-onanimationstart-works-fine ), 建 議 加 上 超 時 保 護 或 通 過 postDelay 替 代onAnimationEnd。

16.【推薦】當 View Animation 執行結束時,呼叫 View.clearAnimation()釋放相關資源。

八、安全

1.【強制】使用 PendingIntent 時,禁止使用空 intent,同時禁止使用隱式 Intent

    說明:

    1) 使用 PendingIntent 時,使用了空 Intent,會導致惡意使用者劫持修改 Intent 的內容。禁止使用一個空 Intent 去構造 PendingIntent,構造 PendingIntent 的 Intent一定要設定 ComponentName 或者 action。

    2) PendingIntent 可以讓其他 APP 中的程式碼像是執行自己 APP 中。 PendingIntent的intent接收方在使用該intent時與傳送方有相同的許可權。在使用PendingIntent時,PendingIntent 中包裝的 intent 如果是隱式的 Intent,容易遭到劫持,導致資訊洩露。

2.【強制】禁止使用常量初始化向量引數構建 IvParameterSpec,建議 IV 通過隨機方式產生。

    說明:

    使用固定初始化向量,結果密碼文字可預測性會高得多,容易受到字典式攻擊。 iv的作用主要是用於產生密文的第一個 block,以使最終生成的密文產生差異(明文相同的情況下),使密碼攻擊變得更為困難,除此之外 iv 並無其它用途。因此 iv 通過隨機方式產生是一種十分簡便、有效的途徑。

3.【強制】將 android:allowbackup 屬性設定為 false,防止 adb backup 匯出資料。

    說明:

    在 AndroidManifest.xml 檔案中為了方便對程式資料的備份和恢復在 Android APIlevel 8 以後增加了 android:allowBackup 屬性值。預設情況下這個屬性值為 true,故當 allowBackup 標誌值為 true 時,即可通過 adb backup 和 adb restore 來備份和恢復應用程式資料。

4.【強制】在實現的 HostnameVerifier 子類中,需要使用 verify 函式效驗伺服器主機名的合法性,否則會導致惡意程式利用中間人攻擊繞過主機名效驗。

    說明:

    在握手期間,如果 URL 的主機名和伺服器的標識主機名不匹配,則驗證機制可以回撥此介面的實現程式來確定是否應該允許此連線。如果回撥內實現不恰當,預設接受所有域名,則有安全風險。

5.【強制】利用 X509TrustManager 子類中的 checkServerTrusted 函式效驗伺服器端證書的合法性。

    說明:

    在實現的 X509TrustManager 子類中未對服務端的證書做檢驗,這樣會導致不被信任的證書繞過證書效驗機制。

6.【強制】META-INF 目錄中不能包含如.apk,.odex,.so 等敏感檔案,該資料夾沒有經過簽名,容易被惡意替換。

7.【強制】Receiver/Provider 不能在毫無許可權控制的情況下,將 android:export 設定為 true。

8.【參考】資料儲存在 Sqlite 或者輕量級儲存需要對資料進行加密,取出來的時候進行解密。

9.【強制】阻止 webview 通過 file:schema 方式訪問本地敏感資料。

10.【強制】不要廣播敏感資訊,只能在本應用使用 LocalBroadcast,避免被別的應用收到,或者 setPackage 做限制。

11.【強制】不要把敏感資訊列印到 log 中。

    說明:

    在 APP 的開發過程中,為了方便除錯,通常會使用 log 函式輸出一些關鍵流程的資訊,這些資訊中通常會包含敏感內容,如執行流程、明文的使用者名稱密碼等,這會讓攻擊者更加容易的瞭解 APP 內部結構方便破解和攻擊,甚至直接獲取到有價值的敏感資訊。

12.【強制】對於內部使用的元件,顯示設定元件的"android:exported"屬性為 false。

    說明:

    Android 應用使用 Intent 機制在元件之間傳遞資料,如果應用在使用 getIntent(),getAction(),Intent.getXXXExtra()獲取到空資料、異常或者畸形資料時沒有進行異常捕獲,應用就會發生 Crash,應用不可使用(本地拒絕服務)。惡意應用可通過向受害者應用傳送此類空資料、異常或者畸形資料從而使應用產生本地拒絕服務。

13.【強制】應用釋出前確保 android:debuggable 屬性設定為 false。

14.【強制】使用 Intent Scheme URL 需要做過濾。

    說明:

    如果瀏覽器支援 Intent Scheme Uri 語法,如果過濾不當,那麼惡意使用者可能通過瀏覽器 js 程式碼進行一些惡意行為,比如盜取 cookie 等。如果使用了 Intent.parseUri函 數 , 獲 取 的 intent 必 須 嚴 格 過 濾 , intent 至 少 包 含addCategory(“android.intent.category.BROWSABLE”) , setComponent(null) ,setSelector(null)3 個策略。

15.【強制】金鑰加密儲存或者經過變形處理後用於加解密運算,切勿硬編碼到程式碼中。

    說明:

    應用程式在加解密時,使用硬編碼在程式中的金鑰,攻擊者通過反編譯拿到金鑰可以輕易解密 APP 通訊資料。

16.【強制】將所需要動態載入的檔案放置在 apk 內部,或應用私有目錄中,如果應用必須要把所載入的檔案放置在可被其他應用讀寫的目錄中(比如 sdcard),建議對不可信的載入源進行完整性校驗和白名單處理,以保證不被惡意程式碼注入。

17.【強制】除非 min API level >=17,請注意 addJavascriptInterface 的使用。

    說明:

    API level>=17,允許 js 被呼叫的函式必須以@JavascriptInterface 進行註解,因此不受影響; 對於 API level < 17,儘量不要使用 addJavascriptInterface,如果一定要用,那麼:

    1) 使用 https 協議載入 URL,使用證書校驗,防止訪問的頁面被篡改掛馬;

    2) 對載入 URL 做白名單過濾、完整性校驗等防止訪問的頁面被篡改;

    3) 如果載入本地 html,應該會 HTML 內建在 APK 中,以及對 HTML 頁面進行完整性校驗。

18.【強制】使用 Android 的 AES/DES/DESede 加密演算法時,不要使用預設的加密模式ECB,應顯示指定使用 CBC 或 CFB 加密模式。

    說明:

    加密模式 ECB、 CBC、 CFB、 OFB 等,其中 ECB 的安全性較弱,會使相同的銘文在不同的時候產生相同的密文,容易遇到字典攻擊,建議使用 CBC 或 CFB 模式。

    1) ECB:Electronic codebook,電子密碼本模式

    2) CBC:Cipher-block chaining,密碼分組連結模式

    3) CFB:Cipher feedback,密文反饋模式

    4) OFB:Output feedback,輸出反饋模式

19.【強制】不要使用 loopback 來通訊敏感資訊。

20.【推薦】對於不需要使用 File 協議的應用,禁用 File 協議,顯式設定 webView.getSettings().setAllowFileAccess(false),對於需要使用 File 協議的應用,禁止 File協議呼叫 JavaScript,顯式設定 webView.getSettings().setJavaScriptEnabled(false)。

21.【強制】Android APP 在 HTTPS 通訊中,驗證策略需要改成嚴格模式。

    說明: AndroidAPP 在 HTTPS 通訊中,使用ALLOW_ALL_HOSTNAME_VERIFIER,表示允許和所有的 HOST 建立 SSL 通訊,這會存在中間人攻擊的風險,最終導致敏感資訊可能會被劫持,以及其他形式的攻擊。

22.【推薦】Android5.0 以後安全性要求 較高的應用 應該使 用 window.setFlag(LayoutParam.FLAG_SECURE) 禁止錄屏。

23.【推薦】zip 中不建議允許../../file 這樣的路徑,可能被篡改目錄結構,造成攻擊。

    說明:當 zip 壓縮包中允許存在"../"的字串,攻擊者可以利用多個"../"在解壓時改變zip 檔案存放的位置,當檔案已經存在是就會進行覆蓋,如果覆蓋掉的檔案是 so、dex 或者 odex 檔案,就有可能造成嚴重的安全問題。

24.【強制】開放的 activity/service/receiver 等需要對傳入的 intent 做合法性校驗。

25.【推薦】加密演算法:使用不安全的 Hash 演算法(MD5/SHA-1)加密資訊,存在被破解的風險,建議使用 SHA-256 等安全性更高的 Hash 演算法。

26.【推薦】Android WebView 元件載入網頁發生證書認證錯誤時,採用預設的處理方法handler.cancel(),停止載入問題頁面。

    說明:

    Android WebView 元件載入網頁發生證書認證錯誤時,會呼叫 WebViewClient 類的onReceivedSslError 方法,如果該方法實現呼叫了 handler.proceed()來忽略該證書錯誤,則會受到中間人攻擊的威脅,可能導致隱私洩露。

27.【推薦】直接傳遞命令字或者間接處理有敏感資訊或操作時,避免使用 socket 實現,使用能夠控制權限校驗身份的方式通訊。

九、其他

1.【強制】不要通過 Msg 傳遞大的物件,會導致記憶體問題。

2.【強制】不能使用 System.out.println 列印 log。

3.【強制】Log 的 tag 不能是" "。