คุณต้องเป็น 64 บิตเพื่อขึ้นเรือข้ามฟากลำนี้

Nov 25 2022
ทำวิศวกรรมย้อนกลับแอป NY Waterway ที่อัปเดตสำหรับ Pixel 7 TLDR: หากคุณมีอุปกรณ์ Android รุ่นใหม่ที่ไม่อนุญาตให้คุณติดตั้ง NY Waterway คุณสามารถดาวน์โหลดแอปพลิเคชันเวอร์ชันแก้ไขของฉันได้ คุณควรระมัดระวังในการติดตั้งแอปพลิเคชันแบบสุ่ม โดยเฉพาะจากแหล่งอื่นที่ไม่ใช่ Play Store อย่างเป็นทางการ เช่น โพสต์ในสื่อกลางนี้โดยคนสุ่มที่คุณไม่เคยได้ยินชื่อ

ทำวิศวกรรมย้อนกลับแอป NY Waterway ที่อัปเดตสำหรับ Pixel 7

ภาพถ่ายโดย Maxwell Ridgeway บน Unsplash

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สำหรับPendingIntentAPI เหล่านี้ flagsพารามิเตอร์จะเป็นตัวสุดท้าย ( int) เสมอ ดังนั้นเราต้องแน่ใจว่าค่านั้นมีFLAG_MUTABLEหรือFLAG_IMMUTABLEตั้งค่าไว้เสมอ เอกสารประกอบ Android SDKเผยให้เห็นว่าค่าของFLAG_MUTABLEis 0x02000000และFLAG_IMMUTABLEis 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 !