Rút gọn, làm rối mã nguồn và tối ưu hoá ứng dụng | Android Developers
Khi bạn thiết kế xây dựng dự án Bất Động Sản bằng trình hỗ trợ Android cho Gradle 3.4.0 trở lên, trình hỗ trợ này sẽ không sử dụng ProGuard để tối ưu hóa mã trong thời hạn biên dịch nữa. Thay vào đó, trình hỗ trợ này sẽ tích hợp với trình biên dịch R8 để giải quyết và xử lý những tác vụ sau đây tại thời gian biên dịch :
- Rút gọn mã (hoặc loại bỏ mã chết (tree-shaking)): nhận diện và loại bỏ một cách an toàn các lớp, trường, phương thức và thuộc tính không sử dụng khỏi ứng dụng cũng như các phần phụ thuộc thư viện của ứng dụng. Đây là một công cụ hữu ích giúp tạm thời khắc phục giới hạn tham chiếu 64k. Ví dụ: nếu bạn chỉ sử dụng một số API của phần phụ thuộc thư viện, tính năng rút gọn này có thể nhận diện mã thư viện mà ứng dụng không sử dụng và xoá chính mã đó khỏi ứng dụng. Để tìm hiểu thêm, hãy tham khảo phần nội dung về cách rút gọn mã.
- Rút gọn tài nguyên: xoá tài nguyên không sử dụng khỏi ứng dụng đóng gói, bao gồm cả tài nguyên không sử dụng đến trong phần phụ thuộc thư viện của ứng dụng. Tính năng này được sử dụng kết hợp với tính năng rút gọn mã sao cho khi xoá mã không sử dụng, những tài nguyên không được tham chiếu đến nữa cũng được xoá một cách an toàn. Để tìm hiểu thêm, hãy tham khảo phần nội dung về cách rút gọn tài nguyên.
- Làm rối: rút ngắn tên lớp và các thành phần của lớp, nhờ đó làm giảm kích thước tệp DEX. Để tìm hiểu thêm, hãy chuyển đến phần nội dung về cách làm rối mã.
- Tối ưu hoá: kiểm tra và viết lại mã để giảm tối đa kích thước tệp DEX của ứng dụng. Ví dụ: nếu R8 phát hiện lệnh rẻ nhánh
else {}
của một câu lệnh if/else nào đó không bao giờ được sử dụng thì R8 sẽ xoá mã của lệnh rẻ nhánhelse {}
đó. Để tìm hiểu thêm, hãy tham khảo phần nội dung tối ưu hoá mã.
Theo mặc định, khi tạo phiên bản phát hành của ứng dụng, R8 sẽ tự động thực hiện các thao tác biên dịch nêu trên. Tuy nhiên, bạn có thể vô hiệu hoá một số thao tác hoặc tuỳ chỉnh hành vi của R8 thông qua các tệp quy tắc ProGuard.
Trên thực tế, R8 kết hợp hiệu quả với tất cả tệp quy tắc ProGuard hiện có, vì vậy, khi cập nhật trình bổ trợ Android cho Gradle để sử dụng R8, bạn không bắt buộc phải thay đổi các quy tắc hiện tại của mình.
Mục Chính
Bật tính năng rút gọn, làm rối mã nguồn và tối ưu hoá
Khi sử dụng Android Studio 3.4 hoặc trình bổ trợ Android cho Gradle 3.4.0 trở lên, R8 là trình biên dịch mặc định, dùng để chuyển đổi mã byte Java của dự án thành định dạng DEX chạy trên nền tảng Android. Tuy nhiên, khi bạn tạo một dự án mới bằng Android Studio, các tính năng rút gọn, làm rối và tối ưu hoá mã sẽ không được bật theo mặc định. Đó là do những tính năng tối ưu hoá tại thời điểm biên dịch này sẽ làm tăng thời gian xây dựng (build time) dự án và có thể gây ra lỗi nếu bạn không tuỳ chỉnh đầy đủ mã cần giữ lại.
Vì vậy, tốt nhất bạn nên bật các tác vụ này tại thời điểm biên dịch khi tạo phiên bản kiểm thử ứng dụng cuối cùng trước khi phát hành. Để bật tính năng rút gọn, làm rối và tối ưu hoá, hãy kèm theo các thành phần sau trong tệp
build.gradle
ở cấp dự án.Groovy
android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. shrinkResources true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles getDefaultProguardFile( 'proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... }Kotlin
android { buildTypes { getByName("release") { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. isMinifyEnabled = true // Enables resource shrinking, which is performed by the // Android Gradle plugin. isShrinkResources = true // Includes the default ProGuard rules files that are packaged with // the Android Gradle plugin. To learn more, go to the section about // R8 configuration files. proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } ... }Tệp cấu hình R8
R8 sử dụng tệp quy tắc ProGuard để chỉnh sửa trạng thái mặc định của ứng dụng và giúp bạn hiểu rõ hơn về cấu trúc của ứng dụng, ví dụ điển hình như lớp đóng vai trò là điểm truy vấn ( entry point ) mã ứng dụng. Bạn hoàn toàn có thể chỉnh sửa 1 số ít tệp quy tắc này. Tuy nhiên, một số ít quy tắc hoàn toàn có thể được tạo tự động hóa bằng những công cụ tại thời gian biên dịch, ví dụ điển hình như AAPT2, hoặc thừa kế từ những phần phụ thuộc thư viện của ứng dụng. Bảng bên dưới miêu tả nguồn gốc của những tệp quy tắc ProGuard được R8 sử dụng .
Nguồn Vị trí Mô tả Android Studio
/proguard-rules.pro Khi tạo một mô-đun mới bằng Android Studio, IDE này sẽ tạo một tệp proguard-rules.pro
trong thư mục gốc của mô-đun đó.
Theo mặc định, tệp này không vận dụng bất kể quy tắc nào. Do đó, hãy thêm những quy tắc ProGuard riêng của bạn vào đây, ví dụ điển hình như những quy tắc lưu giữ ( keep rule ) tùy chỉnh .Trình bổ trợ Android cho Gradle Được trình bổ trợ Android cho Gradle tạo ra tại thời điểm biên dịch. Trình bổ trợ Android cho Gradle sẽ tạo ra proguard-android-optimize.txt
, trong đó chứa các quy tắc hữu ích cho hầu hết các dự án Android và cho phép tạo các chú thích@Keep*
.Theo mặc định, khi tạo một mô-đun mới bằng Android Studio, tệp
build.gradle
cấp mô-đun sẽ bao gồm tệp quy tắc này trong bản phát hành.Lưu ý: Trình bổ trợ Android cho Gradle sẽ bao gồm các tệp quy tắc ProGuard bổ sung được xác định trước, nhưng bạn nên sử dụng
proguard-android-optimize.txt
.Phần phụ thuộc thư viện Thư viện AAR (đề xuất được tự động áp dụng):
/proguard.txt Thư viện JAR:
/META-INF/proguard/ Nếu một thư viện AAR được xuất bản có chứa tệp quy tắc ProGuard riêng và bạn đính kèm thư viện AAR này như một phần phụ thuộc tại thời điểm biên dịch, thì R8 sẽ tự động áp dụng các quy tắc đó khi biên dịch dự án.
Việc đóng gói tệp quy tắc cùng với thư viện AAR sẽ rất có ích nếu thư viện này cần những quy tắc lưu giữ nhất định để hoàn toàn có thể hoạt động giải trí một cách đúng mực. Điều này có nghĩa là nhà tăng trưởng thư viện đã giúp bạn khắc phục sự cố nếu có .Tuy nhiên, nên chú ý quan tâm rằng, những quy tắc ProGuard chỉ là phần bổ trợ nên bạn không hề xóa một số ít quy tắc nhất định trong phần phụ thuộc của thư viện AAR vì điều này hoàn toàn có thể tác động ảnh hưởng đến việc tổng hợp những phần khác trong ứng dụng. Ví dụ : nếu một thư viện chứa một quy tắc dùng để tắt tính năng tối ưu hóa mã, thì quy tắc đó sẽ vô hiệu tính năng tối ưu hóa cho hàng loạt dự án Bất Động Sản .Công cụ đóng gói tài nguyên Android 2 (AAPT2) Sau khi xây dựng dự án của bạn bằng minifyEnabled true
:
/build/intermediates/proguard-rules/debug/aapt_rules.txt AAPT2 sẽ tạo ra các quy tắc lưu giữ dựa trên việc tham chiếu đến các lớp trong tệp kê khai, bố cục và tài nguyên khác của ứng dụng. Ví dụ: AAPT2 bao gồm quy tắc lưu giữ cho mỗi Hoạt động (Activity) mà bạn đăng ký trong tệp kê khai của ứng dụng dưới dạng một điểm truy cập. Tệp cấu hình tuỳ chỉnh Theo mặc định, khi tạo một mô-đun mới bằng Android Studio, IDE này sẽ tạo để bạn có thể thêm vào các quy tắc riêng của mình.
/proguard-rules.pro Bạn có thể thêm các cấu hình bổ sung, sau đó R8 sẽ áp dụng các cấu hình này tại thời điểm biên dịch. Khi bạn thiết lập thuộc tính
minifyEnabled
thànhtrue
, R8 sẽ kết hợp các quy tắc từ tất cả nguồn có sẵn nêu trên. Điều này rất quan trọng và bạn cần ghi nhớ khi khắc phục sự cố với R8, vì các phần phụ thuộc tại thời điểm biên dịch khác, chẳng hạn như các phần phụ thuộc thư viện, có thể thay đổi hành vi của R8 mà bạn không biết.Để xuất ra báo cáo đầy đủ về tất cả quy tắc mà R8 đang áp dụng khi xây dựng dự án, hãy đưa nội dung sau vào tệp
proguard-rules.pro
trong mô-đun của bạn:// You can specify any path and filename. -printconfiguration ~/tmp/full-r8-config.txt
Thêm các cấu hình bổ sung
Khi tạo một dự án hoặc mô-đun mới bằng Android Studio, IDE này sẽ tạo tệp
để bạn đưa vào các quy tắc riêng của mình. Bạn cũng có thể thêm các quy tắc bổ sung trong các tệp khác bằng cách thêm các quy tắc đó vào thuộc tính
/proguard-rules.pro proguardFiles
trong tệpbuild.gradle
trong mô-đun của bạn.Ví dụ: bạn có thể thêm các quy tắc dành riêng cho từng biến thể bản dựng (build variant) bằng cách thêm một thuộc tính
proguardFiles
khác trong khối lệnhproductFlavor
tương ứng. Tệp Gradle dưới đây sẽ thêmflavor2-rules.pro
vào phiên bản sản phẩm (product flavor)flavor2
.
Hiện tại,flavor2
sử dụng cả ba quy tắc ProGuard vì các quy tắc đó cũng được áp dụng trong khốirelease
.Groovy
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). 'proguard-rules.pro' } } flavorDimensions "version" productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } }Kotlin
android { ... buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), // List additional ProGuard rules for the given build type here. By default, // Android Studio creates and includes an empty rules file for you (located // at the root directory of each module). "proguard-rules.pro" ) } } flavorDimensions.add("version") productFlavors { create("flavor1") { ... } create("flavor2") { proguardFile("flavor2-rules.pro") } } }Rút gọn mã
Theo mặc định, tính năng rút gọn mã trong R8 sẽ được bật khi bạn đặt thuộc tính
minifyEnabled
thànhtrue
.Rút gọn mã ( còn được gọi là rung cây ( tree shaking ) ) là quy trình xóa mã mà R8 xác lập là không thiết yếu trong thời hạn chạy ( runtime ). Quá trình này hoàn toàn có thể giảm đáng kể size của ứng dụng trong trường hợp ứng dụng chứa nhiều phần phụ thuộc thư viện nhưng chỉ sử dụng một phần nhỏ công dụng trong đó ví dụ điển hình .
Để rút gọn mã của ứng dụng, thứ nhất, R8 sẽ xác lập toàn bộ điểm truy vấn mã ứng dụng dựa trên nhóm tệp thông số kỹ thuật phối hợp. Các điểm truy vấn này gồm toàn bộ lớp mà nền tảng Android hoàn toàn có thể sử dụng để mở Hoạt động hoặc dịch vụ của ứng dụng. Xuất phát từ mỗi điểm truy vấn, R8 sẽ kiểm tra mã ứng dụng để thiết kế xây dựng sơ đồ toàn bộ phương pháp, biến thành viên và những lớp khác mà ứng dụng hoàn toàn có thể truy vấn trong thời hạn chạy. Mã nào không liên kết với sơ đồ này sẽ được xem là không hề tiếp cận và hoàn toàn có thể bị xóa khỏi ứng dụng .Hình 1 cho thấy một ứng dụng có phần phụ thuộc thư viện trong thời gian chạy. Khi kiểm tra mã ứng dụng, R8 xác định rằng các phương thức
foo()
,faz()
vàbar()
có thể tiếp cận được từ điểm truy cậpMainActivity.class
. Tuy nhiên, ứng dụng không bao giờ sử dụng lớpOkayApi.class
hoặc phương thứcbaz()
của lớp này trong thời gian chạy. Do đó R8 sẽ xoá mã đó trong quá trình rút gọn ứng dụng.
R8 xác định điểm truy cập thông qua các quy tắc
-keep
trong tệp cấu hình R8 của dự án. Điều này có nghĩa là các quy tắc lưu giữ xác định những lớp nào R8 không được loại bỏ trong quá trình rút gọn ứng dụng. Đồng thời, R8 coi những lớp đó là các điểm có thể truy cập vào ứng dụng. Trình bổ trợ Android cho Gradle và AAPT2 tự động tạo các quy tắc lưu giữ (cần thiết cho hầu hết các dự án ứng dụng) cho bạn, chẳng hạn như các hoạt động, khung hiển thị và dịch vụ của ứng dụng. Tuy nhiên, nếu bạn cần tuỳ chỉnh hành vi mặc định này thông qua các quy tắc lưu giữ bổ sung, hãy đọc phần nội dung về cách tuỳ chỉnh mã được giữ lại.trái lại, nếu bạn chỉ muốn giảm size tài nguyên của ứng dụng, hãy chuyển sang phần hướng dẫn cách rút gọn tài nguyên .
Tuỳ chỉnh mã cần lưu giữ
Trong hầu hết các trường hợp, tệp quy tắc ProGuard mặc định (
proguard-android-
) là đủ để R8 xoá mã không sử dụng. Tuy nhiên, trong một số trường hợp R8 không thể phân tích chính xác và có thể xoá nhầm mã mà ứng dụng thực sự cần. Sau đây là một số ví dụ về trường hợp xoá mã không chính xác:
optimize.txt
- Khi ứng dụng gọi một phương thức từ Giao diện gốc Java (JNI)
- Khi ứng dụng tra cứu mã trong thời gian chạy (chẳng hạn như tính năng phản chiếu (reflection))
Việc kiểm thử ứng dụng sẽ giúp phát hiện mọi lỗi phát sinh do xóa mã không tương thích. Tuy nhiên, bạn cũng hoàn toàn có thể kiểm tra xem mã nào đã xóa bằng cách tạo một báo cáo giải trình về những mã đã xóa .
Để khắc phục lỗi và buộc R8 phải giữ lại một số mã nhất định nào đó, hãy thêm một dòng
-keep
trong tệp quy tắc ProGuard. Ví dụ:-keep public class MyClass
Ngoài ra, bạn có thể thêm chú thích
@Keep
vào mã bạn muốn giữ lại. Việc thêm@Keep
vào một lớp sẽ giúp giữ nguyên toàn bộ lớp này. Nếu thêm chú thích này vào phương thức hoặc trường thì phương thức/trường (bao gồm tên của phương thức/trường này) cũng như tên lớp sẽ được giữ nguyên. Lưu ý rằng chú thích này chỉ có sẵn khi sử dụng Thư viện chú thích AndroidX và khi bạn đóng gói tệp quy tắc ProGuard này với trình bổ trợ Android cho Gradle, như được mô tả trong phần nội dung về cách bật tính năng rút gọn ứng dụng.Bạn nên cân nhắc một số thứ khi sử dụng tuỳ chọn
-keep
; để biết thêm thông tin về cách tuỳ chỉnh tệp quy tắc, hãy tham khảo Hướng dẫn sử dụng ProGuard.
Phần Khắc phục sự cố sẽ trình bày các vấn đề phổ biến khác có thể gặp trong quá trình xoá mã.Xoá thư viện gốc
Theo mặc định, những thư viện mã gốc sẽ bị loại ra khỏi những bản phát hành của ứng dụng. Thao tác xóa này gồm có việc xóa bảng hình tượng và thông tin gỡ lỗi trong mọi thư viện gốc mà ứng dụng sử dụng. Việc vô hiệu những thư viện mã gốc giúp giảm đáng kể kích cỡ ứng dụng ; tuy nhiên, bạn không hề chẩn đoán những sự cố hoàn toàn có thể xảy ra trên Google Play Console do thiếu thông tin ( ví dụ điển hình như tên lớp và tên hàm ) .
Hỗ trợ xử lý trục trặc với mã gốc
Google Play Console báo cáo giải trình những trục trặc với mã gốc trong Android vitals. Qua vài bước, bạn hoàn toàn có thể tạo và tải một tệp hình tượng gỡ lỗi gốc lên cho ứng dụng. Tệp này sẽ kích hoạt dấu vết ngăn xếp sự cố gốc tượng trưng ( gồm có tên lớp và tên hàm ) trong Android vitals, được cho phép bạn gỡ lỗi ứng dụng trong bản phát hành chính thức. Các bước này sẽ khác nhau tùy thuộc vào phiên bản của trình hỗ trợ Android cho Gradle được sử dụng trong dự án Bất Động Sản và hiệu quả bản dựng của dự án Bất Động Sản .
Lưu ý:Để tự Phục hồi tên hình tượng trong báo cáo giải trình sự cố, hãy sử dụng công cụ ndk-stack đi kèm với Android NDK .Trình bổ trợ Android cho Gradle phiên bản 4.1 trở lên
Nếu dự án xây dựng một tệp định dạng Android App Bundle thì bạn có thể tự động đưa tệp biểu tượng gỡ lỗi gốc vào tệp định dạng này. Để đưa tệp này vào các bản phát hành, hãy thêm nội dung sau vào tệp
build.gradle
của ứng dụng:
android.buildTypes.release.ndk.debugSymbolLevel = { SYMBOL_TABLE | FULL }
Chọn cấp hình tượng gỡ lỗi từ tùy chọn sau :
- Sử dụng
SYMBOL_TABLE
để lấy tên hàm trong dấu vết ngăn xếp tượng trưng của Play Console.
Cấp độ này sẽ hỗ trợ cấu trúc tombstones.- Sử dụng
FULL
để lấy tên hàm, tệp và số dòng trong dấu vết ngăn xếp tượng trưng của Play Console.Lưu ý:
Tệp biểu tượng gỡ lỗi gốc chỉ được giới hạn trong 300 MB. Nếu mức sử dụng biểu tượng gỡ lỗi quá lớn, hãy dùng
SYMBOL_TABLE
thay vìFULL
để giảm kích thước tệp.Nếu dự án xây dựng một APK, hãy sử dụng chế độ cài đặt bản dựng
build.gradle
được hiển thị trước đó để tạo tệp biểu tượng gỡ lỗi gốc riêng biệt. Tải tệp biểu tượng gỡ lỗi gốc lên Google Play Console theo cách thủ công. Là một phần trong quy trình xây dựng, trình bổ trợ Android cho Gradle sẽ xuất ra tệp này tại vị trí dưới đây trong dự án:
app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
Trình bổ trợ Android cho Gradle phiên bản 4.0 trở về trước (và các hệ thống xây dựng khác)
Là một phần trong quá trình thiết kế xây dựng, trình hỗ trợ Android cho Gradle sẽ lưu giữ một bản sao của những thư viện chứa hình tượng gỡ lỗi trong thư mục của dự án Bất Động Sản. Cấu trúc thư mục này tương tự như như sau :
app/build/intermediates/cmake/universal/release/obj/ ├── armeabi-v7a/ │ ├── libgameengine.so │ ├── libothercode.so │ └── libvideocodec.so ├── arm64-v8a/ │ ├── libgameengine.so │ ├── libothercode.so │ └── libvideocodec.so ├── x86/ │ ├── libgameengine.so │ ├── libothercode.so │ └── libvideocodec.so └── x86_64/ ├── libgameengine.so ├── libothercode.so └── libvideocodec.so
Lưu ý:Nếu sử dụng một mạng lưới hệ thống kiến thiết xây dựng khác thì bạn hoàn toàn có thể chỉnh sửa để tàng trữ những thư viện chứa hình tượng gỡ lỗi trong thư mục có cấu trúc bắt buộc như trên .
- Nén nội dung của thư mục này :
cd app/build/intermediates/cmake/universal/release/obj
zip -r symbols.zip .
Tải tệp
symbols.zip
lên Google Play Console theo cách thủ công.Lưu ý:
Tệp biểu tượng gỡ lỗi chỉ được giới hạn trong 300 MB. Nếu tệp của bạn quá lớn, có thể là do các tệp
.so
chứa bảng biểu tượng (tên hàm) và cũng có thể chứa thông tin gỡ lỗi DWARF (tên tệp và dòng mã). Các dữ liệu này không cần thiết trong quá trình thay thế mã của bạn bằng biểu tượng. Bạn có thể xoá những nội dung này bằng cách chạy lệnh sau:$OBJCOPY --strip-debug lib.so lib.so.sym
trong đó$OBJCOPY
trỏ đến phiên bản cụ thể của ABI mà bạn đang xoá (ví dụ:ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objcopy
).Rút gọn tài nguyên
Tính năng rút gọn tài nguyên chỉ hiệu suất cao khi tích hợp với tính năng rút gọn mã. Sau khi trình rút gọn mã xóa tổng thể mã không sử dụng, trình rút gọn tài nguyên hoàn toàn có thể nhận dạng những tài nguyên nào mà ứng dụng vẫn sử dụng. Điều này đặc biệt quan trọng đúng chuẩn khi bạn thêm những thư viện mã có chứa tài nguyên — bạn phải xóa mã thư viện không còn sử dụng để những tài nguyên thư viện trở thành tài nguyên không được tham chiếu và do đó sẽ bị trình rút gọn tài nguyên xóa bỏ .
Để bật tính năng rút gọn tài nguyên, hãy thiết lập thuộc tính
shrinkResources
thànhtrue
trong tệpbuild.gradle
(cùng vớiminifyEnabled
để bật tính năng rút gọn mã). Ví dụ:Groovy
android { ... buildTypes { release { shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }Kotlin
android { ... buildTypes { getByName("release") { isShrinkResources = true isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" ) } } }Nếu bạn chưa từng tạo ứng dụng bằng cách dùng
minifyEnabled
để rút gọn mã, hãy thử làm điều này trước khi bậtshrinkResources
. Lý do là có thể bạn cần chỉnh sửa tệpproguard-rules.pro
để lưu giữ các lớp hoặc phương thức được tạo hoặc gọi động trước khi bắt đầu xoá tài nguyên.Tuỳ chỉnh tài nguyên cần giữ lại
Nếu muốn giữ lại hoặc loại bỏ tài nguyên nào đó, bạn hãy tạo tệp XML trong dự án bằng một thẻ
, sau đó chỉ định tài nguyên nào cần giữ lại trong thuộc tính
tools:keep
và tài nguyên cần loại bỏ trong thuộc tínhtools:discard
. Cả hai thuộc tính này đều chấp nhận danh sách tên tài nguyên được phân tách nhau bằng dấu phẩy. Bạn có thể sử dụng ký tự dấu hoa thị làm ký tự đại diện.Ví dụ :
Lưu tệp này trong phần tài nguyên của dự án, ví dụ như trong thư mục
res/raw/keep.xml
. Bản dựng sẽ không đóng gói tệp này vào ứng dụng.Bạn có thể cho rằng thật ngớ ngẩn khi chỉ định tài nguyên nào sẽ được huỷ trong khi bạn có thể xoá những tài nguyên này. Tuy nhiên, việc này có thể hữu ích khi sử dụng các biến thể bản dựng. Ví dụ: bạn có thể đặt tất cả tài nguyên của mình vào thư mục chung của dự án, sau đó tạo tệp
keep.xml
khác nhau cho mỗi biến thể bản dựng khi bạn biết một tài nguyên cụ thể nào đó có vẻ như được dùng trong mã (và do đó không bị trình rút gọn xoá đi) nhưng thực sự không được dùng cho biến thể bản dựng đã cho. Cũng có thể các công cụ tạo bản dựng đã xác định không chính xác tài nguyên cần thiết. Vấn đề này có thể xảy ra vì trình biên dịch thêm mã tài nguyên nội tuyến (inline) và sau đó, trình phân tích tài nguyên không nhận thấy sự khác biệt giữa tài nguyên được tham chiếu thực sự và giá trị số nguyên trong mã chứa cùng giá trị.Bật tính năng kiểm tra tham chiếu nghiêm ngặt
Thông thường, trình rút gọn tài nguyên có thể xác định chính xác một tài nguyên nào đó có được sử dụng hay không. Tuy nhiên, nếu mã chứa lời gọi hàm
(hoặc nếu thư viện của bạn thực hiện điều này – thư viện AppCompat), điều đó có nghĩa rằng mã của bạn đang tra cứu tên tài nguyên dựa trên các chuỗi được tạo động. Khi thực hiện điều này, trình rút gọn tài nguyên sẽ hoạt động theo cơ chế bảo vệ mặc định và đánh dấu tất cả tài nguyên có định dạng tên phù hợp dưới dạng tài nguyên đã được sử dụng và không được xoá.
Resources.getIdentifier()Ví dụ: mã sau đây sẽ đánh dấu tất cả tài nguyên có tiền tố
img_
là đã được sử dụng.Kotlin
val name = String.format("img_%1d", angle + 1) val res = resources.getIdentifier(name, "drawable", packageName)Java
String name = String.format("img_%1d", angle + 1); res = getResources().getIdentifier(name, "drawable", getPackageName());Trình rút gọn tài nguyên cũng xem xét tất cả hằng số kiểu chuỗi trong mã cũng như các tài nguyên
res/raw/
khác nhau để tìm các URL tài nguyên có định dạng tương tự nhưfile:///android_res/drawable//ic_plus_anim_016.png
. Nếu tìm thấy các chuỗi này hoặc các chuỗi khác nhưng có thể dùng để tạo các URL như vậy, thì trình rút gọn sẽ không xoá các chuỗi đó.Đây là ví dụ về chế độ rút gọn an toàn được bật theo mặc định.
Tuy nhiên, bạn có thể tắt tính năng xử lý theo hướng “cẩn tắc vô ưu” này và chỉ định trình rút gọn tài nguyên chỉ giữ lại những tài nguyên nào chắc chắn được sử dụng. Để thực hiện việc này, hãy đặtshrinkMode
thànhstrict
trong tệpkeep.xml
như sau:Nếu bật chế độ rút gọn nghiêm ngặt và mã của bạn cũng tham chiếu đến các tài nguyên chứa các chuỗi được tạo động như hiển thị ở trên, thì bạn phải lưu giữ các tài nguyên đó theo cách thủ công thông qua thuộc tính
tools:keep
.Xoá tài nguyên thay thế không sử dụng
Trình rút gọn tài nguyên Gradle chỉ xoá các tài nguyên không được mã ứng dụng tham chiếu đến, nghĩa là trình rút gọn này sẽ không xoá các tài nguyên thay thế cho các cấu hình thiết bị khác nhau. Nếu cần, bạn có thể dùng thuộc tính
resConfigs
của trình bổ trợ Android cho Gradle để xoá các tệp tài nguyên thay thế mà ứng dụng không cần nữa.Ví dụ: nếu bạn đang sử dụng một thư viện có chứa tài nguyên ngôn ngữ (chẳng hạn như AppCompat hoặc Dịch vụ Google Play), thì ứng dụng sẽ bao gồm tất cả chuỗi ngôn ngữ đã dịch cho các thông báo trong những thư viện đó bất kể phần còn lại của ứng dụng có được dịch sang cùng một ngôn ngữ hay không. Nếu chỉ muốn chỉ giữ lại những ngôn ngữ mà ứng dụng hỗ trợ chính thức, bạn có thể chỉ định những ngôn ngữ đó trong thuộc tính
resConfig
. Mọi tài nguyên cho các ngôn ngữ chưa được chỉ định sẽ bị xoá.Đoạn mã sau đây được cho phép số lượng giới hạn tài nguyên ngôn từ chỉ còn tiếng Anh và tiếng Pháp :
Groovy
android { defaultConfig { ... resConfigs "en", "fr" } }Kotlin
android { defaultConfig { ... resourceConfigurations.addAll(listOf("en", "fr")) } }Khi phát hành một ứng dụng theo định dạng Android App Bundle, theo mặc định, chỉ những ngôn từ được định thông số kỹ thuật trên thiết bị của người dùng mới được tải xuống khi thiết lập ứng dụng. Tương tự, chỉ những tài nguyên tương thích với tỷ lệ màn hình hiển thị của thiết bị và những thư viện gốc tương thích với ABI ( giao diện nhị phân ứng dụng ) của thiết bị mới được gồm có trong tệp tải xuống. Để biết thêm thông tin, hãy tìm hiểu thêm thông số kỹ thuật Android App Bundle .
Với những ứng dụng cũ được phát hành bằng APK ( được tạo trước tháng 8 năm 2021 ), bạn hoàn toàn có thể tùy chỉnh tỷ lệ màn hình hiển thị hoặc tài nguyên ABI để đưa vào APK bằng cách tạo nhiều APK, trong đó mỗi tiềm năng có một thông số kỹ thuật thiết bị khác nhau .Hợp nhất các tài nguyên trùng lặp
Theo mặc định, Gradle cũng hợp nhất các tài nguyên có tên giống hệt nhau, chẳng hạn như các đối tượng có thể vẽ có cùng tên có thể nằm trong các thư mục tài nguyên khác nhau. Thuộc tính
shrinkResources
không kiểm soát cũng như không thể kích hoạt hành vi này nhằm tránh lỗi xảy ra khi nhiều tài nguyên có tên khớp với tên đang được tìm kiếm trong mã của bạn.Việc hợp nhất tài nguyên chỉ xảy ra khi hai hoặc nhiều tệp có cùng tên, loại cũng như bộ hạn định ( qualifier ). Gradle sẽ chọn tệp tốt nhất trong số những tệp trùng lặp ( dựa trên thứ tự ưu tiên được diễn đạt bên dưới ) và chỉ truyền duy nhất tài nguyên đó cho AAPT để phân phối trong cấu ứng dụng sau cuối .
Gradle tìm những tài nguyên trùng lặp trong những vị trí sau :
- Các tài nguyên chính, liên kết với nhóm tài nguyên chính, thường nằm trong
src/main/res/
.- Các lớp phủ biến thể (variant overlay) trong loại bản dựng và các phiên bản của bản dựng (build flavor).
- Các phần phụ thuộc thư viện của dự án.
Gradle sẽ hợp nhất những tài nguyên trùng lặp theo thứ tự phân tầng ưu tiên như sau :
Phần phụ thuộc → Chính → Phiên bản của bản dựng → Loại bản dựng
Ví dụ : nếu một tài nguyên nào đó Open lặp lại trong cả tài nguyên chính và phiên bản của bản dựng thì Gradle sẽ chọn tài nguyên trong phiên bản của bản dựng .Nếu các tài nguyên giống hệt nhau xuất hiện trong cùng một nhóm tài nguyên, Gradle không thể hợp nhất các tài nguyên đó và phát sinh lỗi hợp nhất tài nguyên. Điều này có thể xảy ra nếu bạn định nghĩa nhiều nhóm tài nguyên trong thuộc tính
sourceSet
của tệpbuild.gradle
, ví dụ: nếu cảsrc/main/res/
vàsrc/main/res2/
đều chứa các tài nguyên giống nhau.Làm rối mã nguồn
Mục đích của tính năng làm rối mã nguồn là giảm kích cỡ của ứng dụng trải qua việc rút ngắn tên lớp, phương pháp và trường trong ứng dụng. Sau đây là một ví dụ về cách làm rối mã nguồn bằng R8 :
androidx.appcompat.app.ActionBarDrawerToggle$DelegateProvider -> a.a.a.b: androidx.appcompat.app.AlertController -> androidx.appcompat.app.AlertController: android.content.Context mContext -> a int mListItemLayout -> O int mViewSpacingRight -> l android.widget.Button mButtonNeutral -> w int mMultiChoiceItemLayout -> M boolean mShowTitle -> P int mViewSpacingLeft -> j int mButtonPanelSideLayout -> K
Mặc dù tính năng làm rối mã nguồn sẽ không xóa mã khỏi ứng dụng, nhưng bạn hoàn toàn có thể thấy size ứng dụng giảm đáng kể nếu chứa tệp DEX được lập chỉ mục cho nhiều lớp, phương pháp cũng như những trường trong ứng dụng. Tuy nhiên, việc làm rối mã nguồn sẽ đổi tên những phần khác nhau trong mã, yên cầu phải bổ trợ thêm công cụ cho một số ít tác vụ nhất định, ví dụ điển hình như kiểm tra dấu vết ngăn xếp. Để khám phá về dấu vết ngăn xếp sau khi làm rối mã nguồn, vui vẻ đọc phần nội dung về cách giải thuật một dấu vết ngăn xếp đã làm rối mã nguồn .
Ngoài ra, nếu bạn dùng những tên hoàn toàn có thể Dự kiến cho những phương pháp và lớp trong mã của ứng dụng – ví dụ điển hình như khi sử dụng tính năng phản chiếu, bạn nên xem những chữ ký đó như thể những điểm truy vấn và chỉ định quy tắc lưu giữ những chữ ký này như diễn đạt trong phần hướng dẫn cách tùy chỉnh mã cần giữ lại. Các quy tắc này không những sẽ giúp R8 giữ lại mã đó trong DEX sau cuối của ứng dụng mà còn giữ lại tên khởi đầu của ứng dụng .Giải mã dấu vết ngăn xếp đã làm rối mã nguồn
Sau khi R8 làm rối mã nguồn, bạn sẽ gặp khó khăn vất vả khi theo dõi dấu vết ngăn xếp ( nếu không muốn nói là không hề ) vì tên của lớp và phương pháp hoàn toàn có thể đã biến hóa. Để có được dấu vết ngăn xếp bắt đầu, bạn nên truy vết ngược dấu vết ngăn xếp .
Tối ưu hoá mã
Để rút gọn tối đa ứng dụng, R8 sẽ kiểm tra mã ở Lever sâu hơn để xóa những mã nào không còn sử dụng hoặc nếu hoàn toàn có thể, sẽ viết lại mã của bạn để giảm bớt những cụ thể rườm rà. Sau đây là một vài ví dụ về những cách để tối ưu hóa mã :
- Nếu trong một câu lệnh if/else, lệnh rẽ nhánh
else {}
không bao giờ được thực hiện, R8 có thể xoá mã của nhánhelse {}
này.- Nếu mã của bạn gọi một phương thức tại một nơi duy nhất, R8 có thể thay thế nội tuyến (inline) phương thức này bằng cách chèn mã của phương thức tại vị trí của lệnh gọi phương thức đó.
- Nếu R8 xác định một lớp nào chỉ có một lớp con duy nhất và bản thân lớp đó không được tạo bản sao (ví dụ: lớp cơ sở trừu tượng chỉ được một lớp triển khai cụ thể sử dụng), thì R8 có thể kết hợp hai lớp này và xoá một lớp khỏi ứng dụng.
- Để tìm hiểu thêm, hãy đọc các bài đăng trên blog về tối ưu hoá R8 của tác giả Jake Wharton.
R8 không cho phép bạn tuỳ ý tắt hoặc bật tính năng tối ưu hoá hoặc sửa đổi hành vi của tính năng này. Trên thực tế, R8 bỏ qua mọi quy tắc ProGuard dùng để chỉnh sửa tính năng tối ưu hoá mặc định, chẳng hạn như
-optimizations
và-
. Hạn chế này rất quan trọng vì R8 tiếp tục cải thiện, việc duy trì hành vi tiêu chuẩn để tối ưu hoá sẽ giúp nhóm Android Studio dễ dàng khắc phục và giải quyết mọi vấn đề có thể gặp phải.
optimizationpassesLưu ý là việc bật tính năng tối ưu hóa sẽ đổi khác dấu vết ngăn xếp cho ứng dụng. Chẳng hạn như việc cùng dòng sẽ xóa những khung ngăn xếp. Vui lòng xem phần truy vết ngược để tìm hiểu và khám phá cách lấy dấu vết ngăn xếp bắt đầu .
Cho phép tối ưu hoá linh hoạt hơn
R8 bao gồm một bộ tính năng tối ưu hoá bổ sung không được bật lên theo mặc định.
Bạn có thể bật các tính năng tối ưu hoá bổ sung này bằng cách đưa nội dung sau vào tệpgradle.properties
của dự án:android.enableR8.fullMode=true
Các tính năng tối ưu hóa bổ trợ này sẽ làm R8 trở nên độc lạ so với ProGuard, yên cầu bạn phải kèm theo những quy tắc ProGuard bổ trợ để tránh những yếu tố về thời hạn chạy. Ví dụ : giả sử trong mã có tham chiếu đến một lớp trải qua API phản chiếu trong Java ( Java Reflection ). Theo mặc định, R8 giả định rằng bạn có dự tính kiểm tra và thao tác những đối tượng người tiêu dùng của lớp đó trong thời hạn chạy, ngay cả khi mã của bạn thực sự không thực thi điều này, và R8 sẽ tự động hóa giữ lại lớp này cũng như trình khởi chạy tĩnh của lớp .
Tuy nhiên, khi sử dụng ” chính sách khá đầy đủ tính năng ” ( full mode ), R8 không giả định như vậy. Nếu R8 xác nhận mã của bạn không khi nào sử dụng lớp này trong thời hạn chạy thì R8 sẽ xóa lớp này khỏi DEX ở đầu cuối của ứng dụng. Nghĩa là, nếu muốn giữ lớp này cũng như trình khởi chạy tĩnh của lớp, bạn cần thêm quy tắc lưu giữ vào tệp quy tắc để thực thi điều đó .
Nếu gặp sự cố gì khi sử dụng ” chính sách khá đầy đủ tính năng ” của R8, bạn hãy tìm hiểu thêm trang Câu hỏi thường gặp về R8 để tìm giải pháp giải quyết và xử lý khả thi. Nếu không hề xử lý được yếu tố, bạn hãy vui mắt gửi thông tin về lỗi này .Truy vết dấu vết ngăn xếp
Mã do R8 giải quyết và xử lý sẽ biến hóa theo nhiều cách khiến dấu vết ngăn xếp trở nên khó hiểu hơn, vì dấu vết ngăn xếp sẽ không trọn vẹn tương ứng với mã nguồn. Đây hoàn toàn có thể là trường hợp biến hóa số dòng khi thông tin gỡ lỗi không được lưu giữ. Điều này hoàn toàn có thể là do những tính năng tối ưu hóa, ví dụ điển hình như chèn cùng dòng và vẽ đường viền. Yếu tố góp phần lớn nhất là làm rối mã nguồn, nơi mà ngay cả những lớp lẫn phương pháp cũng sẽ đổi khác tên .
Để Phục hồi dấu vết ngăn xếp khởi đầu, R8 cung ứng công cụ truy vết ngược dựa trên dòng lệnh, được đóng gói kèm với gói công cụ dòng lệnh .Để hỗ trợ truy vết ngược các dấu vết ngăn xếp của ứng dụng, bạn nên đảm bảo bản dựng giữ lại đủ thông tin để truy vết bằng cách thêm các quy tắc sau vào tệp
proguard-rules.pro
của mô-đun:-keepattributes LineNumberTable,SourceFile -renamesourcefileattribute SourceFile
Thuộc tính
LineNumberTable
giữ lại thông tin vị trí trong các phương thức mà các vị trí đó được in trong dấu vết ngăn xếp. Thuộc tínhSourceFile
đảm bảo tất cả thời gian chạy tiềm năng đều thực sự in thông tin vị trí. Lệnh-renamesourcefileattribute
đặt tên tệp nguồn trong dấu vết ngăn xếp thànhSourceFile
. Tên tệp nguồn thực tế ban đầu là không cần thiết khi truy vết, vì tệp ánh xạ đã chứa tệp nguồn ban đầu này.R8 tạo một tệp
mapping.txt
mỗi lần chạy. Tệp này chứa thông tin cần thiết để ánh xạ các dấu vết ngăn xếp trở lại dấu vết ngăn xếp ban đầu. Android Studio lưu tệp này trong thư mục.
/build/outputs/mapping/ / Chú ý:
Tệp
mapping.txt
mà studio tạo ra sẽ bị ghi đè mỗi khi bạn tạo dự án. Do đó, bạn phải lưu lại cẩn thận một bản sao mỗi khi đưa ra bản phát hành mới. Việc giữ lại một bản sao của tệpmapping.txt
cho mỗi bản phát hành sẽ rất hữu ích cho quá trình truy vết ngược nếu xảy ra sự cố do người dùng gửi dấu vết ngăn xếp đã làm rối mã từ phiên bản cũ của ứng dụng.Khi phát hành ứng dụng trên Google Play, bạn có thể tải tệp
mapping.txt
lên cho từng phiên bản ứng dụng. Nếu phát hành ứng dụng bằng Android App Bundle, tệp này sẽ được tự động đưa vào như một phần nội dung của gói ứng dụng. Sau đó, Google Play sẽ truy ngược các dấu vết ngăn xếp xuất đến từ các sự cố do người dùng báo cáo, nhờ đó bạn có thể xem xét các dấu vết này trong Play Console. Để tìm hiểu thêm thông tin, vui lòng xem bài viết trên Trung tâm trợ giúp về cách gỡ rối mã nguồn cho các dấu vết ngăn xếp sự cố.Khắc phục sự cố bằng R8
Phần này sẽ diễn đạt một số ít kế hoạch để khắc phục sự cố khi bật tính năng rút gọn, làm rối và tối ưu hóa mã bằng R8. Nếu không tìm thấy giải pháp cho yếu tố của mình bên dưới, bạn hãy đọc trang Câu hỏi thường gặp về R8 và hướng dẫn khắc phục sự cố của ProGuard .
Tạo báo cáo về mã đã xoá (hoặc được giữ lại)
Để khắc phục một số vấn đề liên quan đến R8, bạn có thể xem báo cáo về toàn bộ mã mà R8 đã xoá khỏi ứng dụng của mình. Hãy thêm
-printusage
vào tệp các quy tắc tuỳ chỉnh cho mỗi mô-đun bạn muốn xuất hiện trong báo cáo này. Khi bật R8 và tạo ứng dụng, R8 sẽ xuất ra một báo cáo có đường dẫn và tên tệp như bạn đã chỉ định. Báo cáo về mã đã xoá sẽ có dạng như sau:/usage.txt androidx.drawerlayout.R$attr androidx.vectordrawable.R androidx.appcompat.app.AppCompatDelegateImpl public void setSupportActionBar(androidx.appcompat.widget.Toolbar) public boolean hasWindowFeature(int) public void setHandleNativeActionModesEnabled(boolean) android.view.ViewGroup getSubDecor() public void setLocalNightMode(int) final androidx.appcompat.app.AppCompatDelegateImpl$AutoNightModeManager getAutoNightModeManager() public final androidx.appcompat.app.ActionBarDrawerToggle$Delegate getDrawerToggleDelegate() private static final boolean DEBUG private static final java.lang.String KEY_LOCAL_NIGHT_MODE static final java.lang.String EXCEPTION_HANDLER_MESSAGE_SUFFIX ...
Thay vào đó, nếu muốn xem báo cáo về các điểm truy cập được R8 xác định từ các quy tắc lưu giữ của dự án, bạn hãy thêm
-printseeds
vào tệp quy tắc tuỳ chỉnh của mình. Khi bật R8 và tạo ứng dụng, R8 sẽ xuất ra một báo cáo có đường dẫn và tên tệp như bạn đã chỉ định. Báo cáo về các điểm truy cập được lưu giữ sẽ giống như sau:/seeds.txt com.example.myapplication.MainActivity androidx.appcompat.R$layout: int abc_action_menu_item_layout androidx.appcompat.R$attr: int activityChooserViewStyle androidx.appcompat.R$styleable: int MenuItem_android_id androidx.appcompat.R$styleable: int[] CoordinatorLayout_Layout androidx.lifecycle.FullLifecycleObserverAdapter ...
Khắc phục sự cố liên quan đến việc rút gọn tài nguyên
Khi bạn rút gọn các tài nguyên, cửa sổ Build (Tạo) sẽ trình bày bản tóm tắt về các tài nguyên đã bị xoá khỏi ứng dụng. (Trước tiên, bạn cần phải nhấp vào Toggle view (Chuyển đổi chế độ xem) ở phía bên trái của cửa sổ để hiển thị văn bản đầu ra chi tiết từ Gradle.) Ví dụ:
:android:shrinkDebugResources Removed unused resources: Binary resource data reduced from 2570KB to 1711KB: Removed 33% :android:validateDebugSigning
Gradle cũng tạo một tệp chẩn đoán có tên
resources.txt
trong(chung thư mục với các tệp đầu ra của ProGuard). Tệp này bao gồm chi tiết như tài nguyên nào tham chiếu các tài nguyên khác và tài nguyên nào được sử dụng hoặc bị xoá.
/build/outputs/mapping/release/ Ví dụ: để tìm hiểu tại sao
@drawable/ic_plus_anim_016
vẫn còn trong ứng dụng, bạn hãy mở tệpresources.txt
và tìm kiếm tên tệp đó. Bạn có thể thấy rằng tệp được tham chiếu từ một tài nguyên khác, như thể hiện bên dưới:16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true 16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016
Bây giờ, bạn cần biết tại sao có thể tiếp cận được
@drawable/add_schedule_fab_icon_anim
và nếu tìm kiếm ở phía trên, bạn sẽ thấy tài nguyên đó được liệt kê trong mục “Tài nguyên có thể tiếp cận ở mức cao nhất (root) là:”. Điều này có nghĩa rằng có một tham chiếu mã tớiadd_schedule_fab_icon_anim
(tức là mã nhận dạng tài nguyên có thể vẽ được tìm thấy trong mã có thể tiếp cận).Nếu bạn không sử dụng tùy chọn kiểm tra khắt khe thì những mã nhận dạng tài nguyên sẽ được ghi lại là hoàn toàn có thể tiếp cận được nếu chứa những hằng số chuỗi hoàn toàn có thể dùng để tạo tên tài nguyên cho những tài nguyên được tải động. Trong trường hợp đó, nếu tìm kiếm tác dụng bản dựng cho tên tài nguyên, bạn hoàn toàn có thể thấy thông tin như sau :
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because it format-string matches string pool constant ic_plus_anim_%1$d.
Nếu thấy một trong những chuỗi này và chắc chắn rằng chuỗi đó không được dùng để tải động tài nguyên đã cho, thì bạn có thể sử dụng thuộc tính tools:discard
để thông báo cho hệ thống xây dựng xoá chuỗi đó như mô tả trong phần hướng dẫn cách tuỳ chỉnh tài nguyên cần giữ lại.
Source: https://thomaygiat.com
Category : Kỹ Thuật Số
Chuyển vùng quốc tế MobiFone và 4 điều cần biết – MobifoneGo
Muốn chuyển vùng quốc tế đối với thuê bao MobiFone thì có những cách nào? Đừng lo lắng, bài viết này của MobiFoneGo sẽ giúp…
Cách copy dữ liệu từ ổ cứng này sang ổ cứng khác
Bạn đang vướng mắc không biết làm thế nào để hoàn toàn có thể copy dữ liệu từ ổ cứng này sang ổ cứng khác…
Hướng dẫn xử lý dữ liệu từ máy chấm công bằng Excel
Hướng dẫn xử lý dữ liệu từ máy chấm công bằng Excel Xử lý dữ liệu từ máy chấm công là việc làm vô cùng…
Cách nhanh nhất để chuyển đổi từ Android sang iPhone 11 | https://thomaygiat.com
Bạn đã mua cho mình một chiếc iPhone 11 mới lạ vừa ra mắt, hoặc có thể bạn đã vung tiền và có một chiếc…
Giải pháp bảo mật thông tin trong các hệ cơ sở dữ liệu phổ biến hiện nay
Hiện nay, với sự phát triển mạnh mẽ của công nghệ 4.0 trong đó có internet và các thiết bị công nghệ số. Với các…
4 điều bạn cần lưu ý khi sao lưu dữ liệu trên máy tính
08/10/2020những chú ý khi tiến hành sao lưu dữ liệu trên máy tính trong bài viết dưới đây của máy tính An Phát để bạn…