Tiếp theo của Phần 1 chúng ta sẽ cùng tìm hiểu về các phương pháp còn lại trong việc bảo vệ dữ liệu cá nhân trong quá trình xây dựng ứng dụng Android:
- Chống chụp ảnh màn hình
- Mã hoá dữ liệu cá nhân
- Bảo vệ mã nguồn của ứng dụng
- Cài đặt bảo vệ sinh trắc học
Chống chụp ảnh màn hình
Khi chúng ta đã đảm bảo rằng mọi thông tin log đã không được in ra khi chạy ứng dụng, các cache đã được xoá khi thoát ứng dụng. Nhưng nó vẫn có thể dễ dàng để cho người dùng chụp ảnh màn hình liên quan đến ứng dụng của chúng ta, điều này có thể dẫn đến những vi phạm bản quyền. Ví dụ như việc đọc một truyện tranh có bản quyền, người dùng cần xác nhận thông tin trước khi có thể mở được truyện đọc, nhưng tại đây người dùng vẫn có thể chụp ảnh màn hình cửa từng trang truyện và lưu lại. Nhằm hạn chế việc này, chúng ta có một phương án hiệu quả là chống chụp ảnh màn hình. Chúng ta có thể thêm đoạn code sau vào hàm onCreate() trong Activity của ứng dụng
1 2 | window<span class="token punctuation">.</span><span class="token function">setFlags</span><span class="token punctuation">(</span>WindowManager<span class="token punctuation">.</span>LayoutParams<span class="token punctuation">.</span>FLAG_SECURE<span class="token punctuation">,</span> WindowManager<span class="token punctuation">.</span>LayoutParams<span class="token punctuation">.</span>FLAG_SECURE<span class="token punctuation">)</span> |
Đoạn mã trên sẽ báo đến hệ thống rằng cửa sổ ứng dụng của chúng ta có FLAG_SECURE, cái mà sẽ ngăn chặn việc chụp màn hình dù là cố tình hay vô tình.
Khi build và chạy ứng dụng trên máy thật, tại cửa sổ chương trình chúng ta cố gắng chụp ảnh màn hình sẽ nhìn thấy một tin nhắn dạng Toast có nội dung như sau “Couldn’t capture screenshot” hay “Can’t take screenshot due to security policy”, hoặc một Toast có nội dung tương tự.
Mã hoá dữ liệu cá nhân
Với những thông tin cá nhân quan trọng khi được lưu trữ, hay những file báo cáo, thông tin của ứng dụng được gửi lên server chúng ta nên ưu tiên lựa chọn việc mã hoá thông tin của nó trước khi được lưu xuống bộ nhớ máy hay gửi đi.
Để làm việc này ta có thể sử dụng một thuật toán khá mạnh và phổ biến trong cộng đồng là AES (Advanced Encryption Standard). Thuật toán này có nhiều chế độ mã hoá khác nhau là ECB, CBC, CFB, OFB, CTR trong đó CBC (Cipher Block Channing) là chế độ bảo mật tốt và cũng khá dễ sử dụng.
Sau đây là cách sử dụng thuật toán này trong ứng dụng, đầu tiên ta khai báo thuật toán cần sử dụng, chế độ mã hoá, kiểu Padding là kiểu nào.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">val</span> MODE <span class="token operator">=</span> <span class="token string">"AES/CBC/PKCS5Padding"</span> <span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">val</span> ALGORITHM <span class="token operator">=</span> <span class="token string">"AES"</span> <span class="token keyword">private</span> <span class="token keyword">fun</span> <span class="token function">cipher</span><span class="token punctuation">(</span>opMode<span class="token operator">:</span> Int<span class="token punctuation">,</span> secretKey<span class="token operator">:</span> String<span class="token punctuation">)</span><span class="token operator">:</span> Cipher <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>secretKey<span class="token punctuation">.</span>length <span class="token operator">!=</span> <span class="token number">32</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token function">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"SecretKey length is not 32 chars"</span><span class="token punctuation">)</span> <span class="token keyword">val</span> c <span class="token operator">=</span> Cipher<span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span>MODE<span class="token punctuation">)</span> <span class="token keyword">val</span> sk <span class="token operator">=</span> <span class="token function">SecretKeySpec</span><span class="token punctuation">(</span>secretKey<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span>Charsets<span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">,</span> ALGORITHM<span class="token punctuation">)</span> <span class="token keyword">val</span> iv <span class="token operator">=</span> <span class="token function">IvParameterSpec</span><span class="token punctuation">(</span>secretKey<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span>Charsets<span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">)</span> c<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>opMode<span class="token punctuation">,</span> sk<span class="token punctuation">,</span> iv<span class="token punctuation">)</span> <span class="token keyword">return</span> c <span class="token punctuation">}</span> |
Ở đoạn code trên ta sử dụng thuật toán AES để mã hoá, chế độ mã hoá là CBC, kiểu Padding là “PKCS5Padding“. Hàm “cipher” nhận 2 tham số:
- opMode: chế độ là mã hoá hay giãi mã
- secretKey: khoá dùng đễ mã hoá cũng như giải mã, khoá này phải sử dụng thống nhất trong cả 2 trường hợp mã hoá và giải mã, nếu không thì sẽ không thì giải mã được thông tin đã mã hoá.
Tiếp theo ta tạo hai hàm encrypt để mã hoá và decrypt để giãi mã như bên dưới
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token keyword">fun</span> <span class="token function">encrypt</span><span class="token punctuation">(</span>strToEncrypt<span class="token operator">:</span> String<span class="token punctuation">,</span> secretKey<span class="token operator">:</span> String <span class="token operator">=</span> BuildConfig<span class="token punctuation">.</span>AES_SECRET_KEY<span class="token punctuation">)</span><span class="token operator">:</span> String<span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">val</span> encrypted <span class="token operator">=</span> <span class="token function">cipher</span><span class="token punctuation">(</span> Cipher<span class="token punctuation">.</span>ENCRYPT_MODE<span class="token punctuation">,</span> secretKey <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">doFinal</span><span class="token punctuation">(</span>strToEncrypt<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span>Charsets<span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">String</span><span class="token punctuation">(</span>Base64<span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>encrypted<span class="token punctuation">,</span> Base64<span class="token punctuation">.</span>DEFAULT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> Exception<span class="token punctuation">)</span> <span class="token punctuation">{</span> Timber<span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> <span class="token keyword">fun</span> <span class="token function">decrypt</span><span class="token punctuation">(</span>strToDecrypt<span class="token operator">:</span> String<span class="token operator">?</span><span class="token punctuation">,</span> secretKey<span class="token operator">:</span> String <span class="token operator">=</span> BuildConfig<span class="token punctuation">.</span>AES_SECRET_KEY<span class="token punctuation">)</span><span class="token operator">:</span> String<span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">val</span> byteStr <span class="token operator">=</span> Base64<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span>strToDecrypt<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span>Charsets<span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">,</span> Base64<span class="token punctuation">.</span>DEFAULT<span class="token punctuation">)</span> <span class="token keyword">val</span> decrypted <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span><span class="token function">cipher</span><span class="token punctuation">(</span>Cipher<span class="token punctuation">.</span>DECRYPT_MODE<span class="token punctuation">,</span> secretKey<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">doFinal</span><span class="token punctuation">(</span>byteStr<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> decrypted <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> Exception<span class="token punctuation">)</span> <span class="token punctuation">{</span> Timber<span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span> <span class="token punctuation">}</span> |
- Hàm encrypt: nhận một chuỗi và key đã mã hoá
- Hàm decrypt: nhận chuỗi đã mã hoá và key để giải mã
Đễ mã hoá một chuỗi thông tin trong ứng dụng, chúng ta chỉ cần gọi như sau:
1 2 | <span class="token keyword">val</span> textEncrypt <span class="token operator">=</span> <span class="token function">encrypt</span><span class="token punctuation">(</span><span class="token string">"String for encrypt"</span><span class="token punctuation">,</span> <span class="token string">"password"</span><span class="token punctuation">)</span> |
Với việc giải mã chỉ đơn giản gọi như sau
1 2 | <span class="token keyword">val</span> textDecrypt <span class="token operator">=</span> <span class="token function">decrypt</span><span class="token punctuation">(</span>textEncrypt<span class="token punctuation">,</span> <span class="token string">"password"</span><span class="token punctuation">)</span> |
Chúng ta có thể thấy việc mã hoá khá đơn giản, nhưng nó sẽ giúp thông tin chúng ta được bảo mật hơn, tránh việc truy cập trái phép thông tin.
Bảo vệ mã nguồn của ứng dụng
Khi build một ứng dụng thành file APK để phục vụ cho việc release, tại đây các mã nguồn của ứng dụng sẽ được đóng gói trong file classes.dex.
Việc này dẫn đến tính trạng là nếu ứng dụng chúng ta phân phối cho người dùng thì rất có thể mã nguồn của ứng dụng sẽ dễ dàng bị đọc trộm hoặc tái sử dụng cho mục đích khác. Điều này là hết sức nguy hiểm và dễ dẫn đến những vấn đề nghiêm trọng khi ứng dụng là những sản phẩm thương mại, có liên quan đến thông tin người dùng, thẻ tín dụng, tài khoản ngân hàng…
Nhằm hạn chế việc lộ mã nguồn, chúng ta có thể sủ dụng một phương pháp có sẵn là ProGuard. Đây là một công cụ giúp cho việc tối ưu mã Java bytecode, nó giúp cho các ứng dụng Java và Android giảm đáng kể size khi có thể loại bỏ các biến và hàm không cần dùng đến trong ứng dụng. ProGuard được quảng cáo là làm giảm size của ứng dụng xuống 90% và hoạt động nhanh hơn 20%, nhưng chức năng hữu hiệu của nó còn ở việc có thể hạn chế đến mức thấp nhất việc “reverse” mã nguồn khi nó có thể làm xáo trộn tên của lớp, các biến và hàm đến mức rất khó hiểu để đọc và dịch ngược lại.
Để thực hiện việc này chúng ta cần chú ý đến 2 file sau:
- File build.gradle của ứng dụng: để khai báo việc sử dụng proguard trong bản build nào debug hay release, các phương thức bảo vệ mã nguồn.
- File proguard-rules.pro: khai báo các hàm, các lớp không cần phải ProGuard vì nó liên quan đến ứng dụng thứ 3, hoặc đầu vào của ứng dụng nếu ProGuard thì tên file hoặc lớp sẽ không tìm thấy đúng tên và ứng dụng không thể start.
Đầu tiên chúng ta cần phải xác định việc Proguard nằm trong bản build nào của ứng dụng debug hay release, và thường thì Proguard chỉ thực hiện cho việc release vì lúc này đã hoàn thành và sẵn sàng phân phối đến người sử dụng, sau đây là khai báo cho việc kích hoạt ProGuard cho bản build release từ file build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 | android <span class="token punctuation">{</span> buildTypes <span class="token punctuation">{</span> debug <span class="token punctuation">{</span> testCoverageEnabled <span class="token operator">!</span>project<span class="token punctuation">.</span><span class="token function">hasProperty</span><span class="token punctuation">(</span><span class="token string">'android.injected.invoked.from.ide'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> release <span class="token punctuation">{</span> shrinkResources <span class="token boolean">true</span> minifyEnabled <span class="token boolean">true</span> proguardFiles <span class="token function">getDefaultProguardFile</span><span class="token punctuation">(</span><span class="token string">'proguard-android.txt'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'proguard-rules.pro'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Với khai báo trên chúng ta có thể thấy
- minifyEnabled: dùng để kích hoạt ProGuard, thực hiện việc loại bỏ code không sử dụng, đổi tên class, biến và hàm khi build
- shrinkResources: dùng để loại bỏ các resource không cần sử dụng khi build
- proguardFiles: để khai báo danh sách các lớp, biến, hàm và thư viện không cần phải ProGuard
Tiếp đến, chúng ta sẽ khi báo các lớp, hàm, thư viện chúng ta nên bỏ qua không cần phải ProGuard để đảm bảo chương trình có thể hoạt động đúng. Dưới đây là một file mẫu cho việc bỏ qua việc ProGuard với các thư viện bên ngoài phạm vi ứng dụng của chúng ta
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | # Add project specific ProGuard rules here<span class="token punctuation">.</span> # You can control the set of applied configuration files using the # proguardFiles setting in build<span class="token punctuation">.</span>gradle<span class="token punctuation">.</span> # # For more details<span class="token punctuation">,</span> see # http<span class="token operator">:</span><span class="token operator">/</span><span class="token operator">/</span>developer<span class="token punctuation">.</span>android<span class="token punctuation">.</span>com<span class="token operator">/</span>guide<span class="token operator">/</span>developing<span class="token operator">/</span>tools<span class="token operator">/</span>proguard<span class="token punctuation">.</span>html # If your project uses WebView with JS<span class="token punctuation">,</span> uncomment the following # and specify the fully qualified <span class="token keyword">class</span> <span class="token class-name">name</span> to the JavaScript <span class="token keyword">interface</span> # <span class="token keyword">class</span><span class="token operator">:</span> #<span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">fqcn<span class="token punctuation">.</span>of<span class="token punctuation">.</span>javascript<span class="token punctuation">.</span>interface<span class="token punctuation">.</span>for<span class="token punctuation">.</span>webview</span> <span class="token punctuation">{</span> # <span class="token keyword">public</span> <span class="token operator">*</span><span class="token punctuation">;</span> #<span class="token punctuation">}</span> # Uncomment <span class="token keyword">this</span> to preserve the line number information <span class="token keyword">for</span> # debugging stack traces<span class="token punctuation">.</span> #<span class="token operator">-</span>keepattributes SourceFile<span class="token punctuation">,</span>LineNumberTable # If you keep the line number information<span class="token punctuation">,</span> uncomment <span class="token keyword">this</span> to # hide the original source file name<span class="token punctuation">.</span> #<span class="token operator">-</span>renamesourcefileattribute SourceFile # Support libs <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>app<span class="token punctuation">.</span>Fragment</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>ViewModel</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>os<span class="token punctuation">.</span>Parcelable</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span> CREATOR<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>widget<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">interface</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v7<span class="token punctuation">.</span>widget<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>app<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">interface</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>v4<span class="token punctuation">.</span>app<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>test<span class="token punctuation">.</span>espresso<span class="token punctuation">.</span>IdlingResource</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>test<span class="token punctuation">.</span>espresso<span class="token punctuation">.</span>IdlingRegistry</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>common<span class="token punctuation">.</span>base<span class="token punctuation">.</span>Preconditions</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>*<span class="token operator">*</span> # Guava <span class="token operator">-</span>dontwarn javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn javax<span class="token punctuation">.</span>inject<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Unsafe # Test <span class="token operator">-</span>ignorewarnings <span class="token operator">-</span>dontnote junit<span class="token punctuation">.</span>framework<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontnote junit<span class="token punctuation">.</span>runner<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn android<span class="token punctuation">.</span>test<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn android<span class="token punctuation">.</span>support<span class="token punctuation">.</span>test<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn org<span class="token punctuation">.</span>junit<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn org<span class="token punctuation">.</span>hamcrest<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn com<span class="token punctuation">.</span>squareup<span class="token punctuation">.</span>javawriter<span class="token punctuation">.</span>JavaWriter <span class="token operator">-</span>dontwarn org<span class="token punctuation">.</span>mockito<span class="token punctuation">.</span>*<span class="token operator">*</span> # Retrofit <span class="token operator">-</span>keepattributes Signature<span class="token punctuation">,</span> InnerClasses<span class="token punctuation">,</span> EnclosingMethod <span class="token operator">-</span>keepclassmembers<span class="token punctuation">,</span>allowshrinking<span class="token punctuation">,</span>allowobfuscation <span class="token keyword">interface</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@retrofit2</span><span class="token punctuation">.</span>http<span class="token punctuation">.</span>* <span class="token generics function"><span class="token punctuation"><</span>methods<span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn org<span class="token punctuation">.</span>codehaus<span class="token punctuation">.</span>mojo<span class="token punctuation">.</span>animal_sniffer<span class="token punctuation">.</span>IgnoreJRERequirement <span class="token operator">-</span>dontwarn javax<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn kotlin<span class="token punctuation">.</span>Unit <span class="token operator">-</span>dontwarn retrofit2<span class="token punctuation">.</span>-KotlinExtensions # Glide <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">com<span class="token punctuation">.</span>bumptech<span class="token punctuation">.</span>glide<span class="token punctuation">.</span>module<span class="token punctuation">.</span>GlideModule</span> <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">com<span class="token punctuation">.</span>bumptech<span class="token punctuation">.</span>glide<span class="token punctuation">.</span>module<span class="token punctuation">.</span>AppGlideModule</span> <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">enum</span> com<span class="token punctuation">.</span>bumptech<span class="token punctuation">.</span>glide<span class="token punctuation">.</span>load<span class="token punctuation">.</span>ImageHeaderParser$<span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token punctuation">[</span><span class="token punctuation">]</span> $VALUES<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # RxJava <span class="token operator">&</span> RxAndroid <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>schedulers<span class="token punctuation">.</span>Schedulers</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics function"><span class="token punctuation"><</span>methods<span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>schedulers<span class="token punctuation">.</span>ImmediateScheduler</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token generics function"><span class="token punctuation"><</span>methods<span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>schedulers<span class="token punctuation">.</span>TestScheduler</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token generics function"><span class="token punctuation"><</span>methods<span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>schedulers<span class="token punctuation">.</span>Schedulers</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>util<span class="token punctuation">.</span>unsafe<span class="token punctuation">.</span></span><span class="token operator">*</span>ArrayQueue<span class="token operator">*</span>Field<span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> producerIndex<span class="token punctuation">;</span> <span class="token keyword">long</span> consumerIndex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">rx<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>util<span class="token punctuation">.</span>unsafe<span class="token punctuation">.</span>BaseLinkedQueueProducerNodeRef</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> producerNode<span class="token punctuation">;</span> <span class="token keyword">long</span> consumerNode<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">io<span class="token punctuation">.</span>reactivex<span class="token punctuation">.</span>observers<span class="token punctuation">.</span>DisposableObserver</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # Google Play Service <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>android<span class="token punctuation">.</span>gms<span class="token punctuation">.</span></span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>android<span class="token punctuation">.</span>gms<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>ListResourceBundle</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">getContents</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>android<span class="token punctuation">.</span>gms<span class="token punctuation">.</span>common<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>safeparcel<span class="token punctuation">.</span>SafeParcelable</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> NULL<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepnames <span class="token annotation punctuation">@com</span><span class="token punctuation">.</span>google<span class="token punctuation">.</span>android<span class="token punctuation">.</span>gms<span class="token punctuation">.</span>common<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>KeepName <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token operator">-</span>keepclassmembernames <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@com</span><span class="token punctuation">.</span>google<span class="token punctuation">.</span>android<span class="token punctuation">.</span>gms<span class="token punctuation">.</span>common<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>KeepName <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # Gson <span class="token operator">-</span>keepattributes Signature <span class="token operator">-</span>keepattributes <span class="token operator">*</span>Annotation<span class="token operator">*</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Unsafe</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>gson<span class="token punctuation">.</span>examples<span class="token punctuation">.</span>android<span class="token punctuation">.</span>model<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>gson<span class="token punctuation">.</span>TypeAdapterFactory</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>gson<span class="token punctuation">.</span>JsonSerializer</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>gson<span class="token punctuation">.</span>JsonDeserializer</span> # OkHttp3 <span class="token operator">-</span>keepattributes Signature <span class="token operator">-</span>keepattributes <span class="token operator">*</span>Annotation<span class="token operator">*</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">okhttp3<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">interface</span> <span class="token class-name">okhttp3<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn okhttp3<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontnote okhttp3<span class="token punctuation">.</span>*<span class="token operator">*</span> # Okio <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>Unsafe</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span>file<span class="token punctuation">.</span>* <span class="token operator">-</span>dontwarn org<span class="token punctuation">.</span>codehaus<span class="token punctuation">.</span>mojo<span class="token punctuation">.</span>animal_sniffer<span class="token punctuation">.</span>IgnoreJRERequirement <span class="token operator">-</span>keep <span class="token keyword">interface</span> <span class="token class-name">org<span class="token punctuation">.</span>parceler<span class="token punctuation">.</span>Parcel</span> <span class="token operator">-</span>keep <span class="token annotation punctuation">@org</span><span class="token punctuation">.</span>parceler<span class="token punctuation">.</span>Parcel <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span><span class="token operator">*</span>$$Parcelable <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>invoke<span class="token punctuation">.</span>* <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>codepath<span class="token punctuation">.</span>models</span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token generics function"><span class="token punctuation"><</span>fields<span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # Dagger <span class="token number">2</span> <span class="token operator">-</span>dontwarn com<span class="token punctuation">.</span>google<span class="token punctuation">.</span>errorprone<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span>* <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">javax<span class="token punctuation">.</span>inject<span class="token punctuation">.</span>Provider</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">javax<span class="token punctuation">.</span>inject<span class="token punctuation">.</span>Provider</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">dagger<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers<span class="token punctuation">,</span>allowobfuscation <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@javax</span><span class="token punctuation">.</span>inject<span class="token punctuation">.</span>* <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token annotation punctuation">@dagger</span><span class="token punctuation">.</span>* <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span><span class="token operator">*</span>$$ModuleAdapter <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span><span class="token operator">*</span>$$InjectAdapter <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span><span class="token operator">*</span>$$StaticInjection <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">javax<span class="token punctuation">.</span>inject<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn dagger<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>codegen<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn dagger<span class="token punctuation">.</span>producers<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>dontwarn dagger<span class="token punctuation">.</span>shaded<span class="token punctuation">.</span>auto<span class="token punctuation">.</span>common<span class="token punctuation">.</span>*<span class="token operator">*</span> # LifecycleObserver's empty constructor is considered to be unused by proguard <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>LifecycleObserver</span> <span class="token punctuation">{</span> <span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # ViewModel's empty constructor is considered to be unused by proguard <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>ViewModel</span> <span class="token punctuation">{</span> <span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # Keep Lifecycle State and Event enums values <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>Lifecycle</span>$State <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>Lifecycle</span>$Event <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@android</span><span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>OnLifecycleEvent <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keepclassmembers <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>LifecycleObserver</span> <span class="token punctuation">{</span> <span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>LifecycleObserver</span> <span class="token punctuation">{</span> <span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">implements</span> <span class="token class-name">android<span class="token punctuation">.</span>arch<span class="token punctuation">.</span>lifecycle<span class="token punctuation">.</span>GeneratedAdapter</span> <span class="token punctuation">{</span><span class="token generics function"><span class="token punctuation"><</span>init<span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> # Enum classes <span class="token operator">-</span>keepclassmembers <span class="token keyword">enum</span> <span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span> <span class="token function">valueOf</span><span class="token punctuation">(</span>java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>String<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> # Logs <span class="token operator">-</span>assumenosideeffects <span class="token keyword">class</span> <span class="token class-name">android<span class="token punctuation">.</span>util<span class="token punctuation">.</span>Log</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> <span class="token function">d</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> <span class="token function">w</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> <span class="token function">v</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token operator">*</span><span class="token operator">*</span><span class="token operator">*</span> <span class="token function">i</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> ## Fabric <span class="token operator">-</span>keepattributes SourceFile<span class="token punctuation">,</span>LineNumberTable <span class="token operator">-</span>keep <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token operator">*</span> <span class="token keyword">extends</span> <span class="token class-name">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>Exception</span> <span class="token operator">-</span>keep <span class="token keyword">class</span> <span class="token class-name">com<span class="token punctuation">.</span>crashlytics<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token operator">*</span> <span class="token punctuation">{</span> <span class="token operator">*</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">-</span>dontwarn com<span class="token punctuation">.</span>crashlytics<span class="token punctuation">.</span>*<span class="token operator">*</span> <span class="token operator">-</span>optimizations <span class="token operator">!</span><span class="token keyword">class</span><span class="token operator">/</span>merging<span class="token comment">/* </span> |
Như đã nói việc sử dụng ProGuard sẽ giúp hạn chế đến mức tối đa việc dịch ngược mã nguồn của ứng dụng, giúp hạn chế việc lộ mã nguồn hay đọc trộm các thông tin quan trọng. Chúng rất cần thiết cho việc build ứng dụng phân phối lên Google Play.
Cài đặt bảo vệ sinh trắc học
Ứng dụng của chúng ta có thể được an toàn khi yêu cầu người dùng phải nhập mật khẩu trước khi mở một giao diện nào đó. Nhưng nó cũng sẽ tiềm ẩn rủi ro là mật khẩu của chúng ta vô tình bị đánh cấp bởi một người nào đó hoặc chính là các hackers.
Vì vậy, để bảo đảm rằng chỉ chính chúng ta không phải ai khác có thể truy cập được ứng dụng, các thiết bị điện thoại thông minh hiện nay đã hổ trợ các chứng thực bằng sinh trắc học. Khuôn mặt, mống mắt hay dấu vân tay là những ví dụ điển hình. Chúng ta sẽ đi thiết lập việc chứng thực bằng sinh trắc học trên ứng dụng của chúng ta để đảm bảo rằng chỉ chính chúng ta mới có quyền truy cập vào ứng dụng mà không phải ai khác.
Đầu tiên tại phần build.gradle của ứng dụng, ta khai báo sử dụng thư viện biometric
1 2 | implementation <span class="token string">'androidx.biometric:biometric:1.0.1'</span> |
Kế tiếp, đế ngăn chặn việc crash chúng ta cần kiểm tra thiết bị có hổ trợ việc chứng thực dạng sinh trắc học hay không. Nếu không có thì nhắc nhở người dùng chọn một phương pháp khác thay thế như chứng thực dạng mật khẩu thông thường…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | val biometricManager <span class="token operator">=</span> BiometricManager<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> when <span class="token punctuation">(</span>biometricManager<span class="token punctuation">.</span><span class="token function">canAuthenticate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> BiometricManager<span class="token punctuation">.</span>BIOMETRIC_SUCCESS <span class="token operator">-</span><span class="token operator">></span> <span class="token function">showAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span> BiometricManager<span class="token punctuation">.</span>BIOMETRIC_ERROR_NO_HARDWARE <span class="token operator">-</span><span class="token operator">></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Biometric features no support with current hardware."</span><span class="token punctuation">)</span> <span class="token comment">//Use password authentication in this case</span> BiometricManager<span class="token punctuation">.</span>BIOMETRIC_ERROR_HW_UNAVAILABLE <span class="token operator">-</span><span class="token operator">></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Biometric features are currently unavailable."</span><span class="token punctuation">)</span> BiometricManager<span class="token punctuation">.</span>BIOMETRIC_ERROR_NONE_ENROLLED <span class="token operator">-</span><span class="token operator">></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Please associate a biometric credential with your account."</span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"An unknown error occurred. Please check your Biometric settings"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Nếu thiết bị có hổ trợ chứng thực sinh trắc học, chúng ta sẽ gọi hàm showAuthentication() để hiện thông tin chứng thực đến người dùng.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <span class="token keyword">private</span> fun <span class="token function">showAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> val executor <span class="token operator">=</span> Executors<span class="token punctuation">.</span><span class="token function">newSingleThreadExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> biometricPrompt <span class="token operator">=</span> <span class="token function">BiometricPrompt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> executor<span class="token punctuation">,</span> object <span class="token operator">:</span> BiometricPrompt<span class="token punctuation">.</span><span class="token function">AuthenticationCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> override fun <span class="token function">onAuthenticationError</span><span class="token punctuation">(</span> errorCode<span class="token operator">:</span> Int<span class="token punctuation">,</span> errString<span class="token operator">:</span> CharSequence <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onAuthenticationError</span><span class="token punctuation">(</span>errorCode<span class="token punctuation">,</span> errString<span class="token punctuation">)</span> runOnUiThread <span class="token punctuation">{</span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Authentication error: $errString"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> override fun <span class="token function">onAuthenticationFailed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onAuthenticationFailed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> runOnUiThread <span class="token punctuation">{</span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Authentication failed"</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> override fun <span class="token function">onAuthenticationSucceeded</span><span class="token punctuation">(</span>result<span class="token operator">:</span> BiometricPrompt<span class="token punctuation">.</span>AuthenticationResult<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onAuthenticationSucceeded</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span> runOnUiThread <span class="token punctuation">{</span> <span class="token function">toast</span><span class="token punctuation">(</span><span class="token string">"Authentication succeeded!"</span><span class="token punctuation">)</span> <span class="token function">showListPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> promptInfo <span class="token operator">=</span> BiometricPrompt<span class="token punctuation">.</span>PromptInfo<span class="token punctuation">.</span><span class="token function">Builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string">"Biometric login for your app"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setSubtitle</span><span class="token punctuation">(</span><span class="token string">"Log in using your biometric credential"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setDeviceCredentialAllowed</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> biometricPrompt<span class="token punctuation">.</span><span class="token function">authenticate</span><span class="token punctuation">(</span>promptInfo<span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Hàm này có tác dụng hiển thị giao diện chứng thực như bên dưới.
Nếu người dùng chứng thực thành công thì sẽ gọi hàm showListPersion() đây là hàm hiển thị danh sách người dùng, ta có thể thấy qua hình mình hoạ bên dưới.
Như chúng ta thấy việc sử dụng thư viện chứng thực dạng sinh trắc học khá đơn giản nhưng lại có tính bảo mật rất cao. Chúng ta nên ưu tiên lựa chọn cài đặt nếu ứng dụng của chúng ta cần xác thực trước khi có thể truy cập ứng dụng.