คุณต้องเป็น 64 บิตเพื่อขึ้นเรือข้ามฟากลำนี้
ทำวิศวกรรมย้อนกลับแอป NY Waterway ที่อัปเดตสำหรับ Pixel 7
TLDR : หากคุณมีอุปกรณ์ Android รุ่นใหม่ที่ไม่อนุญาตให้คุณติดตั้ง NY Waterway คุณสามารถดาวน์โหลดแอปพลิเคชันเวอร์ชันแก้ไขของฉันได้ คุณควรระมัดระวังในการติดตั้งแอปพลิเคชันแบบสุ่ม โดยเฉพาะจากแหล่งอื่นที่ไม่ใช่ Play Store อย่างเป็นทางการ เช่น โพสต์ในสื่อกลางนี้โดยคนสุ่มที่คุณไม่เคยได้ยินชื่อ หากคุณต้องการเพิ่มความระมัดระวัง คุณสามารถอ่านล่วงหน้าเพื่อดูว่า APK ได้รับการแก้ไขอย่างไร (และแม้แต่ทำตามขั้นตอนด้วยตัวเองหากต้องการ)
ในปี 2019 Google ได้รองรับ 64 บิตที่จำเป็นสำหรับแอปพลิเคชันใหม่และอัปเดตทั้งหมดใน Play Store ตั้งแต่เดือนสิงหาคม 2021 เป็นต้นไป แอปพลิเคชันที่ไม่รองรับสถาปัตยกรรม 64 บิตจะไม่สามารถใช้งานได้ใน Play Store สำหรับอุปกรณ์ที่รองรับ 64 บิต โดยเฉพาะอย่างยิ่งPixel 7 และ Pixel 7 Pro ใหม่ไม่รองรับการติดตั้งแอปพลิเคชันแบบ 32 บิตเท่านั้น
สำหรับชาวนิวยอร์กที่โดยสารเรือข้ามฟากแม่น้ำฮัดสัน การดำเนินการนี้ค่อนข้างไม่สะดวก เนื่องจากแอปพลิเคชันที่ให้บริการตั๋วอิเล็กทรอนิกส์บนโทรศัพท์ของคุณNY Waterwayนั้นเก่ามาก มีการเผยแพร่ครั้งล่าสุดในเดือนมิถุนายน 2018 และมีไลบรารีเนทีฟสำหรับสถาปัตยกรรม 32 บิตเท่านั้น... ดังนั้น สำหรับผู้ใช้อุปกรณ์ Pixel ใหม่ไม่มีตั๋วอิเล็กทรอนิกส์สำหรับเรือข้ามฟากแม่น้ำฮัดสันสำหรับคุณ!
ตอนนี้ฉันเปลี่ยนมาใช้ iPhone เมื่อหลายปีก่อน แต่ย้อนกลับไปตอนที่ฉันเป็นผู้ใช้ Android ฉันเคยแฮ็กระบบปฏิบัติการและแอปพลิเคชันต่างๆ บ่อยครั้ง เช่น ติดตั้ง ROM แบบกำหนดเองและถอดรหัสแอปพลิเคชัน เพื่อนสนิทของฉันได้รับ Pixel 7 Pro ใหม่และนั่งเรือข้ามฟากที่แม่น้ำฮัดสันตลอดเวลา เขาเลยแหย่ให้ฉันซ่อมแอปนี้ให้เขา ไปเลย!
มองเข้าไปในแอปพลิเคชัน
เริ่มต้นด้วยการตรวจสอบแอปพลิเคชัน NY Waterway เพื่อระบุส่วนที่เป็นแบบ 32 บิตเท่านั้น ซึ่งป้องกันไม่ให้ติดตั้งได้ เมื่อ ใช้apktool
เราสามารถแยกแอปพลิเคชัน Android และตรวจสอบโค้ดได้
$ apktool d ./NYWaterway.apk
I: Using Apktool 2.6.1 on NYWaterway.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/joeywatts/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
$ cd ./NYWaterway
$ ls -l
total 72
-rw-r--r-- 1 joeywatts staff 8797 Nov 21 18:37 AndroidManifest.xml
-rw-r--r-- 1 joeywatts staff 21382 Nov 21 18:37 apktool.yml
drwxr-xr-x 14 joeywatts staff 448 Nov 21 18:37 assets
drwxr-xr-x 5 joeywatts staff 160 Nov 21 18:37 lib
drwxr-xr-x 4 joeywatts staff 128 Nov 21 18:37 original
drwxr-xr-x 178 joeywatts staff 5696 Nov 21 18:37 res
drwxr-xr-x 10 joeywatts staff 320 Nov 21 18:37 smali
drwxr-xr-x 10 joeywatts staff 320 Nov 21 18:37 unknown
ความเข้ากันได้ 64 บิตและไลบรารีเนทีฟ
โดยทั่วไปแล้ว แอปพลิเคชัน Android จะเขียนด้วยภาษา Java หรือ Kotlin ทั้งสองภาษามีเป้าหมายที่ Java Virtual Machine ซึ่งเป็นนามธรรมระดับสูงที่โดยทั่วไปจะป้องกันคุณจากความกังวลเกี่ยวกับความเข้ากันได้เฉพาะแพลตฟอร์ม อย่างไรก็ตาม คุณสามารถใช้Java Native Interface (JNI) เพื่อเรียกใช้โค้ดเนทีฟเฉพาะแพลตฟอร์ม (โดยปกติจะรวบรวมจากภาษาระดับล่าง เช่น C หรือ C++) หากเราดูที่libs
ไดเร็กทอรี เราจะเห็นไลบรารีเนทีฟที่รวมอยู่ในแอป NY Waterway
$ ls -lR lib/*
lib/armeabi:
total 8352
-rw-r--r-- 1 joeywatts staff 177900 Nov 21 18:37 libdatabase_sqlcipher.so
-rw-r--r-- 1 joeywatts staff 1369284 Nov 21 18:37 libsqlcipher.so
-rw-r--r-- 1 joeywatts staff 2314540 Nov 21 18:37 libsqlcipher_android.so
-rw-r--r-- 1 joeywatts staff 402604 Nov 21 18:37 libstlport_shared.so
lib/armeabi-v7a:
total 2552
-rw-r--r-- 1 joeywatts staff 1303788 Nov 21 18:37 libsqlcipher.so
lib/x86:
total 14616
-rw-r--r-- 1 joeywatts staff 1476500 Nov 21 18:37 libdatabase_sqlcipher.so
-rw-r--r-- 1 joeywatts staff 2246448 Nov 21 18:37 libsqlcipher.so
-rw-r--r-- 1 joeywatts staff 3294132 Nov 21 18:37 libsqlcipher_android.so
-rw-r--r-- 1 joeywatts staff 455740 Nov 21 18:37 libstlport_shared.so
ข้อสังเกตอีกประการหนึ่งคือarmeabi
มีx86
ห้องสมุดสี่แห่งในขณะที่armeabi-v7a
มีเพียงแห่งเดียว สำหรับไลบรารีที่จะโหลดโดยแอพ Android จะต้องเรียกเข้าไปjava.lang.System.loadLibrary
หรือ java.lang.Runtime.loadLibrary
การค้นหารหัส Smali สำหรับ "loadLibrary" จะแสดงเพียงที่เดียวที่โหลดไลบรารีดั้งเดิม
$ grep -r loadLibrary smali/
smali//net/sqlcipher/database/SQLiteDatabase.smali: invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
$ grep loadLibrary -A 2 -B 3 smali/net/sqlcipher/database/SQLiteDatabase.smali
:try_start_0
const-string v0, "sqlcipher"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
เราต้องการ ARM 64 บิตlibsqlcipher.so
เพื่อlib/arm64-v8a
ให้แอปพลิเคชันเข้ากันได้กับอุปกรณ์ Pixel รุ่นใหม่ สะดวก SQLCipher เป็นไลบรารีโอเพ่นซอร์ส เมื่อดูรหัสกาวระดับสูงสำหรับการโต้ตอบกับไลบรารี sqlcipher ดั้งเดิม เราสามารถดูเวอร์ชันของไลบรารีที่ใช้ได้
$ grep -ri version smali/net/sqlcipher
smali/net/sqlcipher/database/SQLiteDatabase.smali:.field public static final SQLCIPHER_ANDROID_VERSION:Ljava/lang/String; = "3.5.4"
อัปเกรด SQLCipher เป็น v3.5.5
กระบวนการอัปเกรดจะเกี่ยวข้องกับการแทนที่โค้ด SQLCipher Smali และไลบรารีเนทีฟด้วยโค้ดจากเวอร์ชันที่ใหม่กว่า สิ่งนี้จะทำให้เกิดปัญหาหากพื้นผิว API สาธารณะของ SQLCipher เปลี่ยนไปอย่างมาก (ตัวอย่างเช่น หากฟังก์ชันสาธารณะที่ใช้โดย NY Waterway มีการเปลี่ยนแปลงลายเซ็นหรือถูกลบออก การแทนที่ด้วยเวอร์ชันที่ใหม่กว่าจะทำให้เกิดปัญหา) ทำการสแกนการเปลี่ยนแปลงอย่างรวดเร็วจาก v3.5.4 เป็น v3.5.5 ดูเหมือนว่าจะไม่มีปัญหาที่จะปรากฏที่นี่ ฉันดาวน์โหลดไฟล์ AAR สำหรับ SQLCipher v3.5.5แล้วใช้unzip
เพื่อแตกไฟล์
$ mkdir ../sqlcipher && cd ../sqlcipher
$ unzip ~/Downloads/android-database-sqlcipher-3.5.5.aar
Archive: /Users/joeywatts/Downloads/android-database-sqlcipher-3.5.5.aar
inflating: AndroidManifest.xml
creating: res/
inflating: classes.jar
creating: jni/
creating: jni/arm64-v8a/
creating: jni/armeabi/
creating: jni/armeabi-v7a/
creating: jni/x86/
creating: jni/x86_64/
inflating: jni/arm64-v8a/libsqlcipher.so
inflating: jni/armeabi/libsqlcipher.so
inflating: jni/armeabi-v7a/libsqlcipher.so
inflating: jni/x86/libsqlcipher.so
inflating: jni/x86_64/libsqlcipher.so
Android SDK มีเครื่องมือบรรทัดคำสั่งที่เรียกd8
ว่าสามารถคอมไพล์jar
ไฟล์เป็นรหัสไบต์ของ Android ( classes.dex
ไฟล์) จากนั้นมีเครื่องมืออื่นที่เรียกbaksmali
ว่าสามารถถอดรหัสdex
ไฟล์เป็นsmali
. รวมขั้นตอนเข้าด้วยกัน:
$ export ANDROID_HOME=/Users/joeywatts/Library/Android/sdk
$ $ANDROID_HOME/build-tools/33.0.0/d8 classes.jar \
--lib $ANDROID_HOME/platforms/android-31/android.jar
$ java -jar ../baksmali.jar dis ./classes.dex
$ rm -r ../NYWaterway/smali/net/sqlcipher ../NYWaterway/lib
$ mv out/net/sqlcipher ../NYWaterway/smali/net/sqlcipher
$ mv jni ../NYWaterway/lib
ตอนนี้ เราสามารถสร้างแอปพลิเคชันขึ้นมาใหม่และลงนาม เพื่อให้สามารถติดตั้งบนอุปกรณ์ได้!
$ cd ../NYWaterway
$ apktool b .
$ keytool -genkey -v -keystore my-release-key.keystore -alias alias_name \
-keyalg RSA -keysize 2048 -validity 10000
$ $ANDROID_HOME/build-tools/33.0.0/apksigner sign \
--ks my-release-key.keystore ./dist/NYWaterway.apk
การเพิ่มเวอร์ชัน SDK เป้าหมาย
หากต้องการกำจัดป๊อปอัปนี้ซึ่งระบุว่าแอปพลิเคชันนี้สร้างขึ้นสำหรับ Android เวอร์ชันเก่า เราจำเป็นต้องเพิ่มเวอร์ชัน SDK เป้าหมายในapktool.yml
. แอปพลิเคชันที่มีเป้าหมายเป็น SDK เวอร์ชัน <31 จะไม่ได้รับการยอมรับใน Play Store อีกต่อไป ฉันจึงเลือกที่จะเพิ่มเป็นเวอร์ชันนั้น
การกำหนดเป้าหมายเป็น Android SDK เวอร์ชันใหม่กว่าอาจต้องมีการเปลี่ยนแปลงโค้ด เนื่องจาก API ที่ไม่รองรับจะไม่พร้อมใช้งานใน SDK เวอร์ชันใหม่กว่า NY Waterway ต้องการการเปลี่ยนแปลงหลายอย่างเพื่อกำหนดเป้าหมาย SDK v31
การส่งออกส่วนประกอบที่ปลอดภัยยิ่งขึ้น
หากแอปของคุณกำหนดเป้าหมายเป็น Android 12 ขึ้นไปและมีกิจกรรม บริการ หรือเครื่องรับการแพร่ภาพที่ใช้ตัวกรองความตั้งใจ คุณต้องประกาศandroid:exported
แอตทริบิวต์สำหรับส่วนประกอบแอปเหล่านี้ อย่างชัดเจน
มีกิจกรรมสองสามอย่างและตัวรับหนึ่งตัวที่มี<intent-filter>
s และต้องการandroid:exported="true"
แอตทริบิวต์ที่จะเพิ่มAndroidManifest.xml
ใน
ความผันแปรของเจตนาที่รอดำเนินการ
หากแอปของคุณมีเป้าหมายเป็น Android 12 คุณต้องระบุความไม่แน่นอนของPendingIntent
ออบเจกต์แต่ละรายการที่แอปสร้างขึ้น ข้อกำหนดเพิ่มเติมนี้ช่วยปรับปรุงความปลอดภัยของแอปของคุณ
สิ่งนี้ยุ่งยากกว่าเพราะต้องการให้เราเปลี่ยนรหัสจริง (ตรงข้ามกับการกำหนดค่าโครงการหรือการคัดลอกไลบรารีเวอร์ชันอัปเกรด)
ทุกครั้งที่สร้าง วัตถุ จำเป็น ต้องPendingIntent
ระบุFLAG_MUTABLE
หรือ FLAG_IMMUTABLE
ใน SDK เวอร์ชันก่อนหน้าFLAG_MUTABLE
เป็นค่าเริ่มต้นหากไม่มีการระบุแฟล็ก PendingIntent
วัตถุถูกสร้างขึ้นโดยชุดของวิธีการแบบคงที่ในชั้นเรียน: getActivity
, getActivities
, , getBroadcast
หรือ getService
เราสามารถเริ่มต้นด้วยการค้นหาการเรียกใช้ฟังก์ชันเหล่านั้น
$ grep -r -E "PendingIntent;->(getActivity|getActivities|getBroadcast|getService)" smali
smali/android/support/v4/f/a/ac.smali: invoke-static {p1, v2, v0, v2}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/firebase/iid/r.smali: invoke-static {p0, p1, v0, p4}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/firebase/iid/m.smali: invoke-static {p0, v2, v0, v3}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/firebase/messaging/c.smali: invoke-static {v0, v2, v1, v3}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/common/m.smali: invoke-static {p1, p3, v0, v1}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/common/api/GoogleApiActivity.smali: invoke-static {p0, v0, v1, v2}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/cbx.smali: invoke-static {v1, v2, v0, v3}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/cbx.smali: invoke-static {v2, v7, v1, v7}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/v.smali: invoke-static {v0, v1, v2, v3}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/bj.smali: invoke-static {v1, p2, v0, v2}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/byd.smali: invoke-static {v1, v4, v0, v4}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
smali/com/google/android/gms/c/mr.smali: invoke-static {v1, v3, v0, v3}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
ทำความเข้าใจเกี่ยวกับสมาลี
คำinvoke-static
สั่งรหัสไบต์ใช้รายการของการลงทะเบียนที่จะส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันแบบสแตติก สัญลักษณ์ของฟังก์ชันสแตติกดูเหมือนว่าLandroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
เป็นการแปลโดยตรงจากชื่อคลาสที่มีคุณสมบัติครบถ้วนและลายเซ็นของฟังก์ชัน มันเริ่มต้นด้วยชื่อคลาสLandroid/app/PendingIntent;
(หรือandroid.app.PendingIntent
ในไวยากรณ์ Java ปกติ) จากนั้นชื่อฟังก์ชัน ( ->getBroadcast
) พร้อมด้วยพารามิเตอร์และประเภทการส่งคืน Landroid/content/Context;ILandroid/content/Intent;I
คือพารามิเตอร์ ซึ่งสามารถแบ่งออกเป็นสี่พารามิเตอร์: Landroid/content/Context;
( android.content.Context
), I
( int
), Landroid/content/Intent;
( android.content.Intent
) และI
( int
) สุดท้าย หลังวงเล็บปิดคือประเภทการส่งคืนLandroid/app/PendingIntent;
:
ดังนั้นinvoke-static {v1, v2, v3, v4}
ของฟังก์ชันข้างต้นจะส่งv1
เป็นContext
, เป็น อย่างv2
แรกint
, v3
เป็นIntent
และv4
เป็น int
สำหรับPendingIntent
API เหล่านี้ flags
พารามิเตอร์จะเป็นตัวสุดท้าย ( int
) เสมอ ดังนั้นเราต้องแน่ใจว่าค่านั้นมีFLAG_MUTABLE
หรือFLAG_IMMUTABLE
ตั้งค่าไว้เสมอ เอกสารประกอบ Android SDKเผยให้เห็นว่าค่าของFLAG_MUTABLE
is 0x02000000
และFLAG_IMMUTABLE
is 0x04000000
ในกรณีส่วนใหญ่ พารามิเตอร์สุดท้ายถูกระบุเป็นรีจิสเตอร์ตัวแปรโลคัล ( v#
) ที่เริ่มต้นด้วยค่าคงที่ (เช่นconst/high16 v3, 0x8000000
หรือconst/4 v4, 0x0
) ในกรณีเหล่านี้ เราตรวจสอบได้เล็กน้อยว่าFLAG_MUTABLE
หรือFLAG_IMMUTABLE
ถูกตั้งค่าและอัปเดตค่าคงที่หากไม่ใช่
- const/high16 v3, 0x8000000
+ const/high16 v3, 0xA000000
invoke-static {v1, v2, v0, v3}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
# you may need to change from const/4 to const/high16 to specify the flag
# const/4 is a loading a signed 4-bit integer (seen used to load 0x0).
# const/high16 loads the high 16-bits from a value (the low 16-bits must be 0)
- const/4 v4, 0x0
+ const/high16 v4, 0x2000000
.method private static a(Landroid/content/Context;ILjava/lang/String;Landroid/content/Intent;I)Landroid/app/PendingIntent;
.locals 2
new-instance v0, Landroid/content/Intent;
const-class v1, Lcom/google/firebase/iid/FirebaseInstanceIdInternalReceiver;
invoke-direct {v0, p0, v1}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V
invoke-virtual {v0, p2}, Landroid/content/Intent;->setAction(Ljava/lang/String;)Landroid/content/Intent;
const-string v1, "wrapped_intent"
invoke-virtual {v0, v1, p3}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;
invoke-static {p0, p1, v0, p4}, Landroid/app/PendingIntent;->getBroadcast(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
move-result-object v0
return-object v0
.end method
if (p4 & (FLAG_IMMUTABLE | FLAG_MUTABLE) == 0) {
p4 |= FLAG_MUTABLE;
}
const/high16 v3, 0x6000000 # v3 = FLAG_IMMUTABLE | FLAG_MUTABLE
and-int v2, p4, v3 # v2 = p4 & v3
if-nez v2, :cond_0 # if (v2 != 0) { goto :cond_0; }
const/high16 v3, 0x2000000 # v3 = FLAG_MUTABLE
or-int p4, p4, v3 # p4 = p4 | v3
:cond_0
การเปลี่ยนแปลงการอนุญาตระบบไฟล์
สิทธิ์ของไฟล์ส่วนตัวของไฟล์ไม่ควรได้รับการผ่อนปรนจากเจ้าของอีกต่อไป และการพยายามทำเช่นนั้นโดยใช้MODE_WORLD_READABLE
และ/หรือMODE_WORLD_WRITEABLE
จะทำให้เกิดไฟล์SecurityException
.
มีSharedPreferences
การใช้งาน API บางอย่างที่ใช้MODE_WORLD_READABLE
ในcom/google/android/gms/ads/identifier/AdvertisingIdClient.smali
. ปัญหานี้แก้ไขได้ง่ายมาก เนื่องจากเปลี่ยนจากMODE_WORLD_READABLE
( 0x1
) เป็นMODE_PRIVATE
( 0x0
)
--- a/smali/com/google/android/gms/ads/identifier/AdvertisingIdClient.smali
+++ b/smali/com/google/android/gms/ads/identifier/AdvertisingIdClient.smali
@@ -93,7 +93,7 @@
const-string v4, "google_ads_flags"
- const/4 v5, 0x1
+ const/4 v5, 0x0
invoke-virtual {v2, v4, v5}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
ด้วย Android 6.0 เราได้ยกเลิกการสนับสนุนสำหรับไคลเอนต์ Apache HTTP ตั้งแต่ Android 9 เป็นต้นไป ไลบรารีนั้นจะถูกลบออกจาก bootclasspath และแอปจะไม่พร้อมใช้งานตามค่าเริ่มต้น
NY Waterway ใช้ไคลเอนต์ Apache HTTP เวอร์ชัน Android แต่การแก้ไขสำหรับสิ่งนี้ทำได้ค่อนข้างง่าย — เป็นการเปลี่ยนแปลงอีกครั้งในไฟล์AndroidManifest.xml
.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1490d73..39ccbf3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,6 +16,7 @@
<permission android:name="co.bytemark.nywaterway.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="co.bytemark.nywaterway.permission.C2D_MESSAGE"/>
<application android:allowBackup="false" android:icon="@drawable/icon" android:label="@string/app_name" android:name="co.bytemark.nywaterway2.core.NYWWApp" android:theme="@style/AppTheme">
+ <uses-library android:name="org.apache.http.legacy" android:required="false" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<receiver android:exported="false" android:label="NetworkConnection" android:name="co.bytemark.android.sdk.BytemarkSDK$ConnectionChangeReceiver">
<intent-filter>
หากแอปของคุณกำหนดเป้าหมายเป็น Android 9 ขึ้นไปisCleartextTrafficPermitted()
วิธีการจะส่งกลับfalse
ตามค่าเริ่มต้น หากแอปของคุณต้องเปิดใช้งานข้อความที่ชัดเจนสำหรับโดเมนเฉพาะ คุณต้องตั้งค่าอย่างชัดเจนcleartextTrafficPermitted
สำหรับtrue
โดเมนเหล่านั้นในการกำหนดค่าความปลอดภัยเครือข่ายของแอป
คำขอเครือข่ายล้มเหลวเนื่องจากฟีเจอร์ความปลอดภัยใหม่นี้ วิธีที่ง่ายที่สุดในการทำให้แอปพลิเคชันเข้ากันได้คือการเปลี่ยนแปลงอีกครั้งAndroidManifest.xml
เพื่อเพิ่มandroid:usesCleartextTraffic="true"
แอตทริบิวต์
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 39ccbf3..69b4aa7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,7 +15,7 @@
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission android:name="co.bytemark.nywaterway.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="co.bytemark.nywaterway.permission.C2D_MESSAGE"/>
- <application android:allowBackup="false" android:icon="@drawable/icon" android:label="@string/app_name" android:name="co.bytemark.nywaterway2.core.NYWWApp" android:theme="@style/AppTheme">
+ <application android:allowBackup="false" android:icon="@drawable/icon" android:label="@string/app_name" android:name="co.bytemark.nywaterway2.core.NYWWApp" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<receiver android:exported="false" android:label="NetworkConnection" android:name="co.bytemark.android.sdk.BytemarkSDK$ConnectionChangeReceiver">
หลังจากทำการเปลี่ยนแปลงทั้งหมดข้างต้นแล้ว แอปพลิเคชันก็ทำงานได้สำเร็จโดยไม่มีป๊อปอัปที่สร้างมาสำหรับ Android เวอร์ชันเก่า!
ค่อนข้างคาดไม่ถึง การทำให้มันใช้งานได้กับเวอร์ชัน SDK เป้าหมายที่ใหม่กว่านั้นมีส่วนเกี่ยวข้องมากกว่าการแก้ไขปัญหา 64 บิตจริง ๆ แต่ท้ายที่สุดแล้ว ทุกอย่างก็เป็นเพียงโค้ดและโค้ดก็ไม่มีอะไรต้องกลัว…
ต้องการเชื่อมต่อ? ส่งข้อความถึงฉันทางTwitterหรือLinkedIn !