นอกจากฟีเจอร์และความสามารถใหม่ๆ แล้ว Android 8.0 (API ระดับ 26) ยังมีการเปลี่ยนแปลงลักษณะการทำงานของระบบและ API หลายอย่าง เอกสารนี้จะไฮไลต์การเปลี่ยนแปลงที่สำคัญบางอย่างที่คุณควรทำความเข้าใจและพิจารณาในแอป
การเปลี่ยนแปลงส่วนใหญ่เหล่านี้จะมีผลกับแอปทั้งหมด ไม่ว่าจะกำหนดเป้าหมายเป็น Android เวอร์ชันใดก็ตาม อย่างไรก็ตาม การเปลี่ยนแปลงหลายรายการจะส่งผลต่อแอปที่กำหนดเป้าหมายเป็น Android 8.0 เท่านั้น เพื่อความชัดเจนสูงสุด หน้านี้จึงแบ่งออกเป็น 2 ส่วน ได้แก่ การเปลี่ยนแปลงสำหรับแอปทั้งหมดและการเปลี่ยนแปลงสำหรับแอปที่กำหนดเป้าหมายเป็น Android 8.0
การเปลี่ยนแปลงสำหรับแอปทั้งหมด
การเปลี่ยนแปลงลักษณะการทำงานเหล่านี้มีผลกับ
ขีดจำกัดการดำเนินการในเบื้องหลัง
หนึ่งในการเปลี่ยนแปลงที่ Android 8.0 (ระดับ API 26) นำมาใช้เพื่อปรับปรุงอายุการใช้งานแบตเตอรี่คือ เมื่อแอปของคุณเข้าสู่สถานะแคชโดยไม่มีคอมโพเนนต์ที่ใช้งานอยู่ ระบบจะปล่อย Wakelock ที่แอปถือครองไว้
นอกจากนี้ ระบบจะจำกัดลักษณะการทำงานบางอย่างของแอปที่ไม่ได้ทำงานอยู่เบื้องหน้าเพื่อปรับปรุงประสิทธิภาพของอุปกรณ์ ดังนี้
- ตอนนี้แอปที่ทำงานอยู่เบื้องหลังจะมีขีดจำกัดในการเข้าถึงบริการเบื้องหลัง
- แอปจะใช้ไฟล์ Manifest ของตนเองในการลงทะเบียนสำหรับการออกอากาศโดยนัยส่วนใหญ่ไม่ได้ (ซึ่งก็คือการออกอากาศที่ไม่ได้กำหนดเป้าหมายที่แอปโดยเฉพาะ)
โดยค่าเริ่มต้น ข้อจำกัดเหล่านี้จะมีผลกับแอปที่กำหนดเป้าหมายเป็น O เท่านั้น อย่างไรก็ตาม ผู้ใช้สามารถเปิดใช้ข้อจำกัดเหล่านี้สำหรับแอปใดก็ได้จากหน้าจอการตั้งค่า แม้ว่าแอปจะไม่กำหนดเป้าหมายเป็น O ก็ตาม
Android 8.0 (API ระดับ 26) ยังมีการเปลี่ยนแปลงวิธีการบางอย่างดังต่อไปนี้ด้วย
- ตอนนี้เมธอด
startService()
จะแสดงIllegalStateException
หากแอปที่กำหนดเป้าหมายเป็น Android 8.0 พยายามใช้เมธอดดังกล่าวในสถานการณ์ที่ไม่ได้รับอนุญาตให้สร้างบริการในเบื้องหลัง - เมธอด
Context.startForegroundService()
ใหม่จะเริ่มบริการที่ทำงานอยู่เบื้องหน้า ระบบอนุญาตให้แอปเรียกใช้Context.startForegroundService()
แม้ในขณะที่แอปอยู่ในเบื้องหลัง อย่างไรก็ตาม แอปต้องเรียกใช้เมธอดstartForeground()
ของบริการนั้นภายใน 5 วินาทีหลังจากที่สร้างบริการ
ดูข้อมูลเพิ่มเติมได้ที่ขีดจํากัดของการดำเนินการเบื้องหลัง
ขีดจํากัดตําแหน่งในเบื้องหลังของ Android
แอปที่ทำงานอยู่เบื้องหลังจะได้รับการอัปเดตตำแหน่งน้อยลงเมื่อใช้บนอุปกรณ์ที่ใช้ Android 8.0 เพื่อรักษาแบตเตอรี่ ประสบการณ์ของผู้ใช้ และประสิทธิภาพของระบบ การเปลี่ยนแปลงลักษณะการทํางานนี้มีผลกับแอปทั้งหมดที่ได้รับข้อมูลอัปเดตตําแหน่ง รวมถึงบริการ Google Play
การเปลี่ยนแปลงเหล่านี้มีผลกับ API ต่อไปนี้
- ผู้ให้บริการ Fused Location (FLP)
- การกำหนดเขตพื้นที่เสมือน
- การวัด GNSS
- ผู้จัดการสถานที่
- เครื่องมือจัดการ Wi-Fi
ทําตามขั้นตอนต่อไปนี้เพื่อให้แอปทํางานตามที่คาดไว้
- ตรวจสอบตรรกะของแอปและตรวจสอบว่าคุณใช้ Location API เวอร์ชันล่าสุด
- ทดสอบว่าแอปของคุณแสดงลักษณะการทำงานตามที่คาดไว้สำหรับ Use Case แต่ละรายการ
- ลองใช้ Fused Location Provider (FLP) หรือการกำหนดเขตพื้นที่เสมือนเพื่อจัดการกรณีการใช้งานที่ขึ้นอยู่กับตำแหน่งปัจจุบันของผู้ใช้
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงเหล่านี้ได้ที่ข้อจำกัดเกี่ยวกับตำแหน่งในเบื้องหลัง
แป้นพิมพ์ลัดของแอป
Android 8.0 (API ระดับ 26) มีการเปลี่ยนแปลงต่อไปนี้กับทางลัดของแอป
- การออกอากาศ
com.android.launcher.action.INSTALL_SHORTCUT
ไม่มีผลกับแอปของคุณอีกต่อไป เนื่องจากตอนนี้เป็นการออกอากาศแบบส่วนตัวโดยนัย แต่คุณควรสร้างทางลัดของแอปโดยใช้เมธอดrequestPinShortcut()
จากคลาสShortcutManager
- ตอนนี้ Intent
ACTION_CREATE_SHORTCUT
สามารถสร้างทางลัดของแอปที่คุณจัดการโดยใช้คลาสShortcutManager
แล้ว Intent นี้ยังสร้างทางลัดของ Launcher เดิมที่ไม่โต้ตอบกับShortcutManager
ได้ด้วย ก่อนหน้านี้ Intent นี้สร้างได้เฉพาะทางลัดของ Launcher รุ่นเดิม - ทางลัดที่สร้างโดยใช้
requestPinShortcut()
และทางลัดที่สร้างในกิจกรรมที่จัดการ IntentACTION_CREATE_SHORTCUT
กลายเป็นทางลัดของแอปที่สมบูรณ์แล้ว ด้วยเหตุนี้ แอปจึงอัปเดตได้โดยใช้วิธีการในShortcutManager
- ทางลัดเดิมจะยังคงทำงานตามฟังก์ชันการทำงานจาก Android เวอร์ชันก่อนหน้า แต่คุณต้องแปลงเป็นทางลัดของแอปด้วยตนเองในแอป
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงทางลัดของแอปได้ในคู่มือฟีเจอร์การปักหมุดทางลัดและวิดเจ็ต
ภาษาและการปรับให้เป็นสากล
Android 7.0 (API ระดับ 24) ได้เปิดตัวแนวคิดในการระบุภาษาท้องถิ่นของหมวดหมู่เริ่มต้น แต่ API บางรายการยังคงใช้เมธอด Locale.getDefault()
แบบทั่วไปโดยไม่มีอาร์กิวเมนต์ต่อไป แม้ว่าควรจะใช้ภาษาท้องถิ่นของหมวดหมู่ DISPLAY
เริ่มต้นแทน ใน Android 8.0 (API ระดับ 26) ตอนนี้เมธอดต่อไปนี้ใช้ Locale.getDefault(Category.DISPLAY)
แทน Locale.getDefault()
Locale.getDisplayScript(Locale)
จะกลับไปเป็น Locale.getDefault()
เมื่อค่า displayScript ที่ระบุสำหรับอาร์กิวเมนต์ Locale
ไม่พร้อมใช้งาน
การเปลี่ยนแปลงเพิ่มเติมที่เกี่ยวข้องกับภาษาและการปรับให้เป็นสากลมีดังนี้
- การเรียกใช้
Currency.getDisplayName(null)
จะแสดงข้อยกเว้นNullPointerException
ซึ่งตรงกับลักษณะการทำงานที่บันทึกไว้ - การเปลี่ยนแปลงการแยกวิเคราะห์ชื่อเขตเวลา ก่อนหน้านี้อุปกรณ์ Android ใช้ค่านาฬิกาของระบบที่สุ่มตัวอย่างเมื่อบูตเพื่อแคชชื่อเขตเวลาที่ใช้ในการแยกวิเคราะห์วันที่และเวลา ด้วยเหตุนี้ การแยกวิเคราะห์จึงอาจได้รับผลกระทบในทางลบหากนาฬิกาของระบบไม่ถูกต้องในเวลาบูตหรือในกรณีอื่นๆ ที่พบได้น้อย
ปัจจุบัน ในกรณีทั่วไป ตรรกะการแยกวิเคราะห์จะใช้ ICU และค่านาฬิกาของระบบปัจจุบันเมื่อแยกวิเคราะห์ชื่อเขตเวลา การเปลี่ยนแปลงนี้ให้ผลลัพธ์ที่ถูกต้องมากขึ้น ซึ่งอาจแตกต่างจาก Android เวอร์ชันเก่าเมื่อแอปของคุณใช้คลาสอย่าง
SimpleDateFormat
- Android 8.0 (API ระดับ 26) จะอัปเดต ICU เป็นเวอร์ชัน 58
กรอบเวลาการแจ้งเตือน
หากแอปใช้สิทธิ์ SYSTEM_ALERT_WINDOW
และหน้าต่างประเภทใดประเภทหนึ่งต่อไปนี้เพื่อพยายามแสดงหน้าต่างแจ้งเตือนเหนือแอปอื่นๆ และหน้าต่างของระบบ
...แล้วหน้าต่างเหล่านี้จะปรากฏใต้หน้าต่างที่ใช้ประเภท TYPE_APPLICATION_OVERLAY
window เสมอ หากแอปกำหนดเป้าหมายเป็น Android 8.0 (API ระดับ 26) แอปจะใช้ประเภท TYPE_APPLICATION_OVERLAY
window เพื่อแสดงหน้าต่างการแจ้งเตือน
ดูข้อมูลเพิ่มเติมได้ที่ส่วนประเภทหน้าต่างทั่วไปสำหรับหน้าต่างข้อความแจ้งภายในการเปลี่ยนแปลงลักษณะการทํางานของแอปที่กําหนดเป้าหมายเป็น Android 8.0
การป้อนข้อมูลและการนำทาง
เมื่อมีแอป Android ใน ChromeOS และอุปกรณ์รูปแบบอื่นๆ ที่มีขนาดใหญ่ เช่น แท็บเล็ต เราพบว่าการใช้การไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ในแอป Android กลับมาได้รับความนิยมอีกครั้ง ใน Android 8.0 (API ระดับ 26) เราได้แก้ไขการใช้แป้นพิมพ์เป็นอุปกรณ์อินพุตการไปยังส่วนต่างๆ อีกครั้ง ซึ่งทำให้การไปยังส่วนต่างๆ ด้วยปุ่มลูกศรและแท็บมีความน่าเชื่อถือและคาดการณ์ได้มากขึ้น
โดยเฉพาะอย่างยิ่ง เราได้ทำการเปลี่ยนแปลงต่อไปนี้กับลักษณะการโฟกัสองค์ประกอบ
-
หากคุณยังไม่ได้กำหนดสีสถานะโฟกัสสำหรับออบเจ็กต์
View
(ออบเจ็กต์ที่วาดได้ในส่วนหน้าหรือพื้นหลัง) ตอนนี้เฟรมเวิร์กจะกำหนดสีไฮไลต์โฟกัสเริ่มต้นสำหรับView
ไฮไลต์โฟกัสนี้เป็นภาพวาดแบบกระเพื่อมที่อิงตามธีมของกิจกรรมหากไม่ต้องการให้ออบเจ็กต์
View
ใช้ไฮไลต์เริ่มต้นนี้เมื่อได้รับโฟกัส ให้ตั้งค่าแอตทริบิวต์android:defaultFocusHighlightEnabled
เป็นfalse
ในไฟล์ XML เลย์เอาต์ที่มีView
หรือส่งfalse
ไปยังsetDefaultFocusHighlightEnabled()
ในตรรกะ UI ของแอป - หากต้องการทดสอบว่าการป้อนข้อมูลด้วยแป้นพิมพ์ส่งผลต่อโฟกัสขององค์ประกอบ UI อย่างไร ให้เปิดใช้ตัวเลือกการวาด > แสดงขอบเขตเลย์เอาต์สำหรับนักพัฒนาซอฟต์แวร์ ใน Android 8.0 ตัวเลือกนี้จะแสดงไอคอน "X" เหนือองค์ประกอบที่มีโฟกัสอยู่
นอกจากนี้ องค์ประกอบแถบเครื่องมือทั้งหมดใน Android 8.0 จะเป็นกลุ่มการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์โดยอัตโนมัติ ซึ่งช่วยให้ผู้ใช้ไปยังส่วนต่างๆ ในแถบเครื่องมือแต่ละรายการได้ง่ายขึ้น
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีปรับปรุงการรองรับการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ภายในแอปได้จากคู่มือการรองรับการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์
กรอกข้อมูลเว็บฟอร์มอัตโนมัติ
เนื่องจากเฟรมเวิร์กการป้อนข้อความอัตโนมัติของ Android มีการรองรับฟังก์ชันการป้อนข้อความอัตโนมัติในตัวแล้ว เราจึงมีการเปลี่ยนแปลงวิธีการต่อไปนี้ที่เกี่ยวข้องกับออบเจ็กต์ WebView
สำหรับแอปที่ติดตั้งอยู่ในอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26)
WebSettings
-
- ตอนนี้เมธอด
getSaveFormData()
แสดงผลfalse
ก่อนหน้านี้ เมธอดนี้จะแสดงผลเป็นtrue
แทน - การเรียกใช้
setSaveFormData()
ไม่มีผลอีกต่อไป
- ตอนนี้เมธอด
WebViewDatabase
-
- การเรียกใช้
clearFormData()
ไม่มีผลอีกต่อไป - ตอนนี้เมธอด
hasFormData()
จะแสดงfalse
ก่อนหน้านี้วิธีนี้แสดงผลtrue
เมื่อแบบฟอร์มมีข้อมูล
- การเรียกใช้
การช่วยเหลือพิเศษ
Android 8.0 (API ระดับ 26) มีการเปลี่ยนแปลงต่อไปนี้เกี่ยวกับการช่วยเหลือพิเศษ
-
ตอนนี้เฟรมเวิร์กการช่วยเหลือพิเศษจะแปลงท่าทางสัมผัสด้วยการแตะสองครั้งทั้งหมดเป็นการดำเนินการ
ACTION_CLICK
การเปลี่ยนแปลงนี้จะช่วยให้ TalkBack ทำงานได้คล้ายกับบริการการช่วยเหลือพิเศษอื่นๆ มากขึ้นหาก
View
ออบเจ็กต์ของแอปใช้การจัดการการสัมผัสที่กําหนดเอง คุณควรตรวจสอบว่าออบเจ็กต์เหล่านั้นยังคงทํางานร่วมกับ TalkBack ได้ คุณอาจต้องลงทะเบียนตัวแฮนเดิลการคลิกที่ออบเจ็กต์View
ใช้ หาก TalkBack ยังคงไม่รู้จักท่าทางสัมผัสที่ทำกับวัตถุเหล่านี้ ให้ลบล้างView
performAccessibilityAction()
- ตอนนี้บริการการช่วยเหลือพิเศษจะรับรู้อินสแตนซ์
ClickableSpan
ทั้งหมดภายในออบเจ็กต์TextView
ของแอป
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีทําให้แอปเข้าถึงได้ง่ายขึ้นได้ที่การช่วยเหลือพิเศษ
เครือข่ายและการเชื่อมต่อ HTTP(S)
Android 8.0 (API ระดับ 26) มีการเปลี่ยนแปลงลักษณะการทำงานต่อไปนี้ใน เครือข่ายและการเชื่อมต่อ HTTP(S)
- คำขอ OPTIONS ที่ไม่มีเนื้อหาจะมีส่วนหัว
Content-Length: 0
ก่อนหน้านี้ไม่มีส่วนหัวContent-Length
- HttpURLConnection จะปรับ URL ที่มีเส้นทางว่างให้เป็นมาตรฐานโดยใส่เครื่องหมายทับต่อท้ายชื่อโฮสต์หรือชื่อโดเมน เช่น แปลง
http://example.com
เป็นhttp://example.com/
- ตัวเลือกพร็อกซีที่กำหนดเองซึ่งตั้งค่าผ่าน ProxySelector.setDefault() จะกำหนดเป้าหมายเฉพาะที่อยู่ (รูปแบบ โฮสต์ และพอร์ต) ของ URL ที่ขอเท่านั้น ดังนั้น การเลือกพร็อกซีอาจอิงตามค่าเหล่านั้นเท่านั้น URL ที่ส่งไปยังตัวเลือกพร็อกซีที่กำหนดเองจะไม่รวมเส้นทาง พารามิเตอร์การค้นหา หรือข้อมูลโค้ดของ URL ที่ขอ
- URI ต้องไม่มีป้ายกำกับที่ว่างเปล่า
ก่อนหน้านี้ แพลตฟอร์มรองรับวิธีแก้ปัญหาเพื่อยอมรับป้ายกำกับว่างในชื่อโฮสต์ ซึ่งเป็นการใช้ URI ที่ผิดกฎหมาย วิธีแก้ปัญหานี้มีไว้เพื่อเพิ่มความเข้ากันได้กับ libcore เวอร์ชันเก่า นักพัฒนาซอฟต์แวร์ที่ใช้ API อย่างไม่ถูกต้องจะเห็นข้อความ ADB ว่า "URI example..com มีป้ายกำกับว่างในชื่อโฮสต์ ข้อมูลนี้อยู่ในรูปแบบที่ไม่ถูกต้องและระบบจะไม่ยอมรับใน Android เวอร์ชันในอนาคต" Android 8.0 นำวิธีแก้ปัญหานี้ออก ระบบจะแสดงผล Null สำหรับ URI ที่ไม่ถูกต้อง
- การใช้งาน HttpsURLConnection ของ Android 8.0 จะไม่ใช้โปรโตคอล TLS/SSL เวอร์ชันที่ไม่ปลอดภัยเป็นทางเลือก
- มีการเปลี่ยนแปลงการจัดการการเชื่อมต่อ HTTP(S) ของ Tunnel ดังนี้
- เมื่อส่งผ่านการเชื่อมต่อ HTTPS ผ่านการเชื่อมต่อ ระบบจะใส่หมายเลขพอร์ต (:443) ในบรรทัดโฮสต์อย่างถูกต้องเมื่อส่งข้อมูลนี้ไปยังเซิร์ฟเวอร์กลาง ก่อนหน้านี้ หมายเลขพอร์ตจะปรากฏในบรรทัด CONNECT เท่านั้น
- ระบบจะไม่ส่งส่วนหัว User-Agent และ Proxy-Authorization จากคำขอที่ส่งผ่านอุโมงค์ไปยังเซิร์ฟเวอร์พร็อกซีอีกต่อไป
ระบบจะไม่ส่งส่วนหัวการให้สิทธิ์พร็อกซีใน Http(s)URLConnection ที่มีการเชื่อมต่อไปยังพร็อกซีอีกต่อไปเมื่อตั้งค่าอุโมงค์ข้อมูล แต่ระบบจะสร้างส่วนหัวการให้สิทธิ์พร็อกซีแทน และส่งไปยังพร็อกซีเมื่อพร็อกซีดังกล่าวส่ง HTTP 407 เพื่อตอบกลับคำขอแรก
ในทํานองเดียวกัน ระบบจะไม่คัดลอกส่วนหัว User-Agent จากคําขอที่ส่งผ่านอุโมงค์ไปยังคําขอพร็อกซีที่ตั้งค่าอุโมงค์อีกต่อไป แต่ไลบรารีจะสร้างส่วนหัว User Agent สําหรับคําขอนั้นแทน
- เมธอด
send(java.net.DatagramPacket)
จะแสดงข้อยกเว้น SocketException หากเมธอด connect() ที่เรียกใช้ก่อนหน้านี้ไม่สำเร็จ- DatagramSocket.connect() จะตั้งค่า pendingSocketException หากมีข้อผิดพลาดภายใน ก่อนที่จะเป็น Android 8.0 การเรียกใช้ recv() ตามมาจะทำให้เกิด SocketException แม้ว่าการเรียกใช้ send() จะสำเร็จก็ตาม เพื่อความสอดคล้อง ตอนนี้การโทรทั้งสองจะมี SocketException
- InetAddress.isReachable() จะพยายามใช้ ICMP ก่อนเปลี่ยนไปใช้โปรโตคอล TCP Echo
- โฮสต์บางรายการที่บล็อกพอร์ต 7 (TCP Echo) เช่น google.com อาจเข้าถึงได้หากยอมรับโปรโตคอล ICMP Echo
- สําหรับโฮสต์ที่เข้าถึงไม่ได้จริงๆ การเปลี่ยนแปลงนี้หมายความว่าระบบจะใช้เวลานานขึ้น 2 เท่าก่อนที่จะมีการเรียกกลับ
บลูทูธ
Android 8.0 (API ระดับ 26) ทำการเปลี่ยนแปลงต่อไปนี้กับความยาวของข้อมูลที่เมธอด ScanRecord.getBytes()
retrieving ดึงข้อมูล
- เมธอด
getBytes()
จะไม่คาดเดาจำนวนไบต์ที่ได้รับ ดังนั้น แอปไม่ควรใช้จำนวนไบต์ขั้นต่ำหรือสูงสุดที่แสดงผล แต่ควรประเมินความยาวของอาร์เรย์ผลลัพธ์แทน - อุปกรณ์ที่เข้ากันได้กับบลูทูธ 5 อาจแสดงผลความยาวข้อมูลเกินกว่าค่าสูงสุดก่อนหน้านี้ที่ประมาณ 60 ไบต์
- หากอุปกรณ์ระยะไกลไม่ตอบสนองการสแกน ระบบอาจแสดงผลน้อยกว่า 60 ไบต์ด้วย
การเชื่อมต่อที่ราบรื่น
Android 8.0 (API ระดับ 26) ปรับปรุงการตั้งค่า Wi-Fi หลายอย่างเพื่อให้เลือกเครือข่าย Wi-Fi ที่มอบประสบการณ์การใช้งานที่ดีที่สุดแก่ผู้ใช้ได้ง่ายขึ้น การเปลี่ยนแปลงที่เจาะจงมีดังนี้
- ปรับปรุงความเสถียรและความน่าเชื่อถือ
- UI ที่อ่านง่ายขึ้น
- เมนูค่ากำหนด Wi-Fi แบบรวมที่ใช้งานง่าย
- ในอุปกรณ์ที่รองรับ การเปิดใช้งาน Wi-Fi โดยอัตโนมัติเมื่ออยู่ใกล้เครือข่ายที่บันทึกไว้ซึ่งมีคุณภาพสูง
ความปลอดภัย
Android 8.0 มีการเปลี่ยนแปลงที่เกี่ยวข้องกับความปลอดภัยดังต่อไปนี้
- แพลตฟอร์มนี้ไม่สนับสนุน SSLv3 อีกต่อไป
- เมื่อสร้างการเชื่อมต่อ HTTPS กับเซิร์ฟเวอร์ที่ใช้การเจรจาต่อรองเวอร์ชันโปรโตคอล TLS อย่างไม่ถูกต้อง
HttpsURLConnection
จะไม่พยายามแก้ปัญหาชั่วคราวด้วยการกลับไปใช้โปรโตคอล TLS เวอร์ชันเก่าแล้วลองใหม่อีกต่อไป - Android 8.0 (API ระดับ 26) ใช้ตัวกรองการประมวลผลที่ปลอดภัย (SECCOMP) กับแอปทั้งหมด รายการ syscall ที่อนุญาตจะจํากัดไว้เฉพาะ syscall ที่แสดงผ่าน bionic แม้ว่าจะมี syscall อื่นๆ อีกหลายรายการที่ระบุไว้เพื่อใช้งานร่วมกันได้แบบย้อนหลัง แต่เราไม่แนะนำให้ใช้
- ตอนนี้ออบเจ็กต์
WebView
ของแอปจะทำงานในโหมดหลายกระบวนการ ระบบจะจัดการเนื้อหาเว็บในกระบวนการแยกต่างหากจากกระบวนการของแอปที่มีเนื้อหาเว็บเพื่อเพิ่มความปลอดภัย -
คุณไม่สามารถถือว่า APK อยู่ในไดเรกทอรีที่มีชื่อลงท้ายด้วย -1 หรือ -2 ได้อีกต่อไป แอปควรใช้
sourceDir
เพื่อรับไดเรกทอรี และไม่ควรใช้รูปแบบไดเรกทอรีโดยตรง - ดูข้อมูลเกี่ยวกับการปรับปรุงความปลอดภัยที่เกี่ยวข้องกับการใช้ไลบรารีแบบเนทีฟได้ที่ไลบรารีแบบเนทีฟ
นอกจากนี้ Android 8.0 (API ระดับ 26) ยังมาพร้อมกับการเปลี่ยนแปลงต่อไปนี้ซึ่งเกี่ยวข้องกับการติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มาที่ไม่รู้จัก
- ตอนนี้ค่าของการตั้งค่าเดิม
INSTALL_NON_MARKET_APPS
จะเป็น 1 เสมอ หากต้องการตรวจสอบว่าแหล่งที่มาที่ไม่รู้จักสามารถติดตั้งแอปโดยใช้โปรแกรมติดตั้งแพ็กเกจได้หรือไม่ คุณควรใช้ผลลัพธ์ของcanRequestPackageInstalls()
แทน - หากคุณพยายามเปลี่ยนค่าของ
INSTALL_NON_MARKET_APPS
โดยใช้setSecureSetting()
ระบบจะแสดงUnsupportedOperationException
หากต้องการป้องกันไม่ให้ผู้ใช้ติดตั้งแอปที่ไม่รู้จักโดยใช้แหล่งที่มาที่ไม่รู้จัก คุณควรใช้DISALLOW_INSTALL_UNKNOWN_SOURCES
ข้อจำกัดของผู้ใช้แทน -
โปรไฟล์ที่มีการจัดการที่สร้างในอุปกรณ์ที่ใช้ Android 8.0 (API ระดับ 26) จะเปิดใช้ข้อจำกัด
DISALLOW_INSTALL_UNKNOWN_SOURCES
ของผู้ใช้โดยอัตโนมัติ สำหรับโปรไฟล์ที่มีการจัดการที่มีอยู่ซึ่งอัปเกรดเป็น Android 8.0 ระบบจะเปิดใช้ข้อจำกัดDISALLOW_INSTALL_UNKNOWN_SOURCES
ของผู้ใช้โดยอัตโนมัติ เว้นแต่ว่าเจ้าของโปรไฟล์จะปิดใช้ข้อจำกัดนี้อย่างชัดเจน (ก่อนการอัปเกรด) โดยการตั้งค่าINSTALL_NON_MARKET_APPS
เป็น 1
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการติดตั้งแอปที่ไม่รู้จักได้ที่คู่มือสิทธิ์ในการติดตั้งแอปที่ไม่รู้จัก
ดูหลักเกณฑ์เพิ่มเติมเกี่ยวกับการทำให้แอปปลอดภัยยิ่งขึ้นได้ที่ความปลอดภัยสำหรับนักพัฒนาแอป Android
ความเป็นส่วนตัว
Android 8.0 (API ระดับ 26) ทำการเปลี่ยนแปลงต่อไปนี้ที่เกี่ยวข้องกับความเป็นส่วนตัวในแพลตฟอร์ม
- ปัจจุบันแพลตฟอร์มจะจัดการกับตัวระบุในลักษณะที่ต่างออกไป
-
สําหรับแอปที่ติดตั้งก่อนการอัปเดต OTA เป็น Android 8.0 (API ระดับ 26) (API ระดับ 26) ค่าของ
ANDROID_ID
จะยังคงเหมือนเดิม เว้นแต่จะมีการถอนการติดตั้งแล้วติดตั้งอีกครั้งหลังจาก OTA หากต้องการเก็บค่าไว้หลังจากการถอนการติดตั้ง OTA นักพัฒนาแอปสามารถเชื่อมโยงค่าเก่าและค่าใหม่ได้โดยใช้ การสำรองข้อมูลคีย์/ค่า - สำหรับแอปที่ติดตั้งในอุปกรณ์ที่ใช้ Android 8.0 ตอนนี้ค่าของ
ANDROID_ID
จะกำหนดขอบเขตตามคีย์ App Signing ของแอปแต่ละรายการและตามผู้ใช้แต่ละราย ค่าของANDROID_ID
จะไม่ซ้ำกันสำหรับชุดค่าผสมของคีย์การรับรองแอป ผู้ใช้ และอุปกรณ์แต่ละชุด ด้วยเหตุนี้ แอปที่มีคีย์การรับรองต่างกันซึ่งทำงานในอุปกรณ์เครื่องเดียวกันจึงไม่เห็นรหัส Android เดียวกันอีกต่อไป (แม้ว่าจะเป็นผู้ใช้รายเดียวกันก็ตาม) - ค่าของ
ANDROID_ID
จะไม่เปลี่ยนแปลงเมื่อถอนการติดตั้งหรือติดตั้งแพ็กเกจใหม่ ตราบใดที่มีคีย์ Signing เหมือนกัน (และแอปไม่ได้ติดตั้งก่อน OTA ใน Android เวอร์ชัน 8.0) - ค่าของ
ANDROID_ID
จะไม่มีการเปลี่ยนแปลงแม้ว่าการอัปเดตระบบจะทําให้คีย์การรับรองแพ็กเกจเปลี่ยนแปลงก็ตาม - ในอุปกรณ์ที่มาพร้อมกับบริการ Google Play และรหัสโฆษณา คุณต้องใช้
รหัสโฆษณา ระบบมาตรฐานที่ใช้งานง่ายในการสร้างรายได้จากแอป
รหัสโฆษณาคือรหัสที่ไม่ซ้ำกันซึ่งผู้ใช้รีเซ็ตได้สำหรับใช้กับโฆษณา ซึ่งให้บริการโดยบริการ Google Play
ผู้ผลิตอุปกรณ์รายอื่นๆ ควรให้บริการ
ANDROID_ID
ต่อไป
-
สําหรับแอปที่ติดตั้งก่อนการอัปเดต OTA เป็น Android 8.0 (API ระดับ 26) (API ระดับ 26) ค่าของ
- การค้นหาพร็อพเพอร์ตี้ระบบ
net.hostname
ให้ผลลัพธ์เป็นค่าว่าง
การบันทึกข้อยกเว้นที่ตรวจไม่พบ
หากแอปติดตั้ง Thread.UncaughtExceptionHandler
ที่ไม่ได้เรียกใช้ Thread.UncaughtExceptionHandler
เริ่มต้น ระบบจะไม่หยุดแอปเมื่อเกิดข้อยกเว้นที่ตรวจไม่พบ เริ่มตั้งแต่ Android 8.0 (API ระดับ 26) ระบบจะบันทึกสแต็กเทรซข้อยกเว้นในสถานการณ์นี้ แต่ในแพลตฟอร์มเวอร์ชันก่อนหน้า ระบบจะไม่บันทึกสแต็กเทรซข้อยกเว้น
เราขอแนะนำให้การติดตั้งใช้งาน Thread.UncaughtExceptionHandler
แบบกำหนดเองเรียกใช้ตัวแฮนเดิลเริ่มต้นเสมอ แอปที่เป็นไปตามคำแนะนำนี้จะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงใน Android 8.0
การเปลี่ยนแปลงลายเซ็น findViewById()
ตอนนี้อินสแตนซ์ทั้งหมดของเมธอด findViewById()
จะแสดงผล
<T extends View> T
แทน View
การเปลี่ยนแปลงนี้ส่งผลดังต่อไปนี้
- ซึ่งอาจส่งผลให้โค้ดที่มีอยู่มีประเภทผลลัพธ์ที่ไม่ชัดเจน เช่น หากมีทั้ง
someMethod(View)
และsomeMethod(TextView)
ที่ใช้ผลลัพธ์ของการเรียกfindViewById()
- เมื่อใช้ภาษาแหล่งที่มาของ Java 8 จะต้องแคสต์เป็น
View
อย่างชัดแจ้งเมื่อประเภทผลลัพธ์ไม่จำกัด (เช่นassertNotNull(findViewById(...)).someViewMethod())
- การลบล้างวิธีการ
findViewById()
ที่ไม่ใช่ขั้นสุดท้าย (เช่นActivity.findViewById()
) จะต้องอัปเดตประเภทผลลัพธ์
การเปลี่ยนแปลงสถิติการใช้งานผู้ให้บริการรายชื่อติดต่อ
ใน Android เวอร์ชันก่อนหน้า คอมโพเนนต์ผู้ให้บริการรายชื่อติดต่อช่วยให้นักพัฒนาซอฟต์แวร์รับข้อมูลการใช้งานของรายชื่อติดต่อแต่ละรายการได้ ข้อมูลการใช้งานนี้จะแสดงข้อมูลของอีเมลและหมายเลขโทรศัพท์แต่ละรายการที่เชื่อมโยงกับรายชื่อติดต่อ รวมถึงจํานวนครั้งที่ติดต่อรายชื่อติดต่อและเวลาที่ติดต่อครั้งล่าสุด แอปที่ขอสิทธิ์ READ_CONTACTS
จะอ่านข้อมูลนี้ได้
แอปจะยังคงอ่านข้อมูลนี้ได้หากขอสิทธิ์ READ_CONTACTS
ใน Android 8.0 (API ระดับ 26) ขึ้นไป การค้นหาข้อมูลการใช้งานจะแสดงผลค่าโดยประมาณแทนที่จะเป็นค่าที่แน่นอน ระบบ Android จะเก็บค่าที่แน่นอนไว้ภายใน ดังนั้นการเปลี่ยนแปลงนี้จึงไม่ส่งผลต่อ API เติมข้อความอัตโนมัติ
การเปลี่ยนแปลงลักษณะการทํางานนี้มีผลต่อพารามิเตอร์การค้นหาต่อไปนี้
การจัดการคอลเล็กชัน
AbstractCollection.removeAll()
และ AbstractCollection.retainAll()
ในปัจจุบันจะส่ง NullPointerException
เสมอ และก่อนหน้านี้ไม่มีการแสดง NullPointerException
เมื่อคอลเล็กชันว่างเปล่า การเปลี่ยนแปลงนี้ทําให้ลักษณะการทํางานสอดคล้องกับเอกสารประกอบ
Android Enterprise
Android 8.0 (API ระดับ 26) เปลี่ยนลักษณะการทำงานของ API และฟีเจอร์บางอย่างสำหรับแอประดับองค์กร ซึ่งรวมถึงเครื่องมือควบคุมนโยบายด้านอุปกรณ์ (DPC) การเปลี่ยนแปลงมีดังนี้
- ลักษณะการทำงานใหม่เพื่อช่วยให้แอปรองรับโปรไฟล์งานในอุปกรณ์ที่มีการจัดการแบบครบวงจร
- การเปลี่ยนแปลงการจัดการการอัปเดตระบบ การยืนยันแอป และการตรวจสอบสิทธิ์เพื่อเพิ่มความสมบูรณ์ของอุปกรณ์และระบบ
- การปรับปรุงประสบการณ์ของผู้ใช้สำหรับการเตรียมอุปกรณ์ การแจ้งเตือน หน้าจอรายการล่าสุด และ VPN ที่เปิดอยู่ตลอดเวลา
หากต้องการดูการเปลี่ยนแปลงทั้งหมดระดับองค์กรใน Android 8.0 (API ระดับ 26) และเรียนรู้ว่า การเปลี่ยนแปลงนี้อาจส่งผลต่อแอปของคุณอย่างไร โปรดอ่าน Android ใน Enterprise
แอปที่กําหนดเป้าหมายเป็น Android 8.0
การเปลี่ยนแปลงลักษณะการทำงานเหล่านี้มีผลกับแอปที่กำหนดเป้าหมายเป็น Android 8.0 (API ระดับ 26) ขึ้นไปเท่านั้น แอปที่คอมไพล์กับ Android 8.0
หรือตั้งค่า targetSdkVersion
เป็น Android 8.0 ขึ้นไปต้องแก้ไข
แอปเพื่อรองรับลักษณะการทำงานเหล่านี้อย่างถูกต้อง ในกรณีที่เกี่ยวข้องกับแอป
กรอบเวลาการแจ้งเตือน
แอปที่ใช้สิทธิ์ SYSTEM_ALERT_WINDOW
จะไม่สามารถแสดงหน้าต่างประเภทต่อไปนี้เหนือแอปอื่นๆ และหน้าต่างของระบบเพื่อแสดงหน้าต่างแจ้งเตือนได้อีกต่อไป
แต่แอปต้องใช้หน้าต่างประเภทใหม่ที่เรียกว่า TYPE_APPLICATION_OVERLAY
แทน
เมื่อใช้ประเภทหน้าต่าง TYPE_APPLICATION_OVERLAY
เพื่อแสดงหน้าต่างแจ้งเตือนสําหรับแอป โปรดคํานึงถึงลักษณะต่อไปนี้ของประเภทหน้าต่างใหม่
- หน้าต่างการแจ้งเตือนของแอปจะปรากฏใต้หน้าต่างระบบที่สำคัญเสมอ เช่น แถบสถานะและ IME
- ระบบย้ายหรือปรับขนาดหน้าต่างที่ใช้หน้าต่างประเภท
TYPE_APPLICATION_OVERLAY
เพื่อปรับปรุงการนำเสนอหน้าจอได้ - เมื่อเปิดหน้าต่างแจ้งเตือน ผู้ใช้จะเข้าถึงการตั้งค่าเพื่อบล็อกแอปไม่ให้แสดงหน้าต่างการแจ้งเตือนที่ใช้ประเภทหน้าต่าง
TYPE_APPLICATION_OVERLAY
ได้
การแจ้งเตือนการเปลี่ยนแปลงเนื้อหา
Android 8.0 (API ระดับ 26) เปลี่ยนแปลงลักษณะการทํางานของ ContentResolver.notifyChange()
และ registerContentObserver(Uri, boolean, ContentObserver)
สําหรับแอปที่กําหนดเป้าหมายเป็น Android 8.0
ตอนนี้ API เหล่านี้กำหนดให้ต้องกำหนด ContentProvider
ที่ถูกต้องสำหรับหน่วยงานใน URI ทั้งหมด การกําหนด ContentProvider
ที่ถูกต้องพร้อมสิทธิ์ที่เกี่ยวข้องจะช่วยปกป้องแอปของคุณจากการเปลี่ยนแปลงเนื้อหาจากแอปที่เป็นอันตราย และป้องกันไม่ให้แอปที่เป็นอันตรายรั่วไหลข้อมูลที่อาจเป็นข้อมูลส่วนตัว
ดูโฟกัส
ออบเจ็กต์ View
ที่คลิกได้ยังโฟกัสได้โดยค่าเริ่มต้น หากต้องการให้ออบเจ็กต์ View
คลิกได้แต่โฟกัสไม่ได้ ให้ตั้งค่าแอตทริบิวต์
android:focusable
เป็น false
ในไฟล์ XML เลย์เอาต์ที่มี View
หรือส่ง false
ไปยัง setFocusable()
ในตรรกะ UI ของแอป
การจับคู่ User Agent ในการตรวจหาเบราว์เซอร์
Android 8.0 (API ระดับ 26) ขึ้นไปจะมีสตริงตัวระบุบิลด์ OPR
การจับคู่รูปแบบบางอย่างอาจทําให้ตรรกะการตรวจหาเบราว์เซอร์ระบุเบราว์เซอร์ที่ไม่ใช่ Opera เป็น Opera อย่างไม่ถูกต้อง
ตัวอย่างการจับคู่รูปแบบดังกล่าวอาจเป็นดังนี้
if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}
หากต้องการหลีกเลี่ยงปัญหาที่เกิดจากการระบุที่ไม่ถูกต้องดังกล่าว ให้ใช้สตริงอื่นที่ไม่ใช่ OPR
เป็นรายการที่ตรงกันของรูปแบบสําหรับเบราว์เซอร์ Opera
ความปลอดภัย
การเปลี่ยนแปลงต่อไปนี้ส่งผลต่อความปลอดภัยใน Android 8.0 (API ระดับ 26)
- หากการกำหนดค่าความปลอดภัยของเครือข่ายของแอปเลือกไม่รองรับการรับส่งข้อมูลแบบข้อความธรรมดา (Cleartext) ออบเจ็กต์
WebView
ของแอปจะเข้าถึงเว็บไซต์ผ่าน HTTP ไม่ได้ ออบเจ็กต์WebView
แต่ละรายการต้องใช้ HTTPS แทน - ระบบได้นำการตั้งค่าอนุญาตแหล่งที่มาที่ไม่รู้จักออกแล้ว แทนที่ด้วยสิทธิ์ติดตั้งแอปที่ไม่รู้จักซึ่งจะจัดการการติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มาที่ไม่รู้จัก ดูข้อมูลเพิ่มเติมเกี่ยวกับสิทธิ์ใหม่นี้ได้ในคู่มือสิทธิ์ในการติดตั้งแอปที่ไม่รู้จัก
ดูหลักเกณฑ์เพิ่มเติมเกี่ยวกับการทำให้แอปปลอดภัยยิ่งขึ้นได้ที่ความปลอดภัยสำหรับนักพัฒนาแอป Android
การเข้าถึงบัญชีและการค้นพบ
ใน Android 8.0 (API ระดับ 26) แอปจะเข้าถึงบัญชีผู้ใช้ไม่ได้อีกต่อไป เว้นแต่โปรแกรมตรวจสอบสิทธิ์จะเป็นเจ้าของบัญชีหรือผู้ใช้ให้สิทธิ์เข้าถึง สิทธิ์ GET_ACCOUNTS
ไม่เพียงพออีกต่อไป แอปควรใช้ AccountManager.newChooseAccountIntent()
หรือวิธีการที่เจาะจงสำหรับโปรแกรมตรวจสอบสิทธิ์เพื่อรับสิทธิ์เข้าถึงบัญชี หลังจากได้รับสิทธิ์เข้าถึงบัญชีแล้ว แอปจะเรียกใช้ AccountManager.getAccounts()
เพื่อเข้าถึงบัญชีได้
Android 8.0 เลิกใช้งาน
LOGIN_ACCOUNTS_CHANGED_ACTION
แอป
ควรใช้ addOnAccountsUpdatedListener()
เพื่อรับข้อมูลอัปเดตเกี่ยวกับบัญชีระหว่างรันไทม์แทน
สำหรับข้อมูลเกี่ยวกับ API ใหม่และวิธีการใหม่ๆ ที่เพิ่มเข้ามาสำหรับการเข้าถึงและการค้นพบบัญชี โปรดดูสิทธิ์เข้าถึงและการค้นพบบัญชีในส่วน API ใหม่ของเอกสารนี้
ความเป็นส่วนตัว
การเปลี่ยนแปลงต่อไปนี้ส่งผลต่อความเป็นส่วนตัวใน Android 8.0 (API ระดับ 26)
-
พร็อพเพอร์ตี้ของระบบ
net.dns1
,net.dns2
,net.dns3
และnet.dns4
จะใช้งานไม่ได้อีกต่อไป ซึ่งเป็นการเปลี่ยนแปลงที่ช่วยปรับปรุงความเป็นส่วนตัวบนแพลตฟอร์ม -
หากต้องการรับข้อมูลเครือข่าย เช่น เซิร์ฟเวอร์ DNS แอปที่มี
ACCESS_NETWORK_STATE
สิทธิ์จะลงทะเบียนออบเจ็กต์NetworkRequest
หรือNetworkCallback
ได้ คลาสเหล่านี้พร้อมใช้งานใน Android 5.0 (API ระดับ 21) ขึ้นไป -
เลิกใช้งาน Build.SERIAL แล้ว
แอปที่ต้องการทราบหมายเลขซีเรียลของฮาร์ดแวร์ควรใช้เมธอด
Build.getSerial()
ใหม่แทน ซึ่งต้องใช้สิทธิ์READ_PHONE_STATE
-
LauncherApps
API ไม่อนุญาตให้แอปในโปรไฟล์งานรับข้อมูลเกี่ยวกับโปรไฟล์หลักอีกต่อไป เมื่อผู้ใช้อยู่ในโปรไฟล์งานLauncherApps
API จะทํางานราวกับว่าไม่มีการติดตั้งแอปในโปรไฟล์อื่นๆ ภายในกลุ่มโปรไฟล์เดียวกัน และเช่นเคย การพยายามเข้าถึงโปรไฟล์ที่ไม่เกี่ยวข้องจะทำให้ SecurityException
สิทธิ์
ก่อนที่จะมีการเปิดตัว Android 8.0 (API ระดับ 26) หากแอปขอสิทธิ์ขณะรันไทม์และได้รับสิทธิ์ ระบบก็จะให้สิทธิ์ที่เหลือแก่แอปอย่างไม่ถูกต้อง ซึ่งสิทธิ์เหล่านั้นเป็นของกลุ่มสิทธิ์เดียวกันและได้ลงทะเบียนไว้ในไฟล์ Manifest
สำหรับแอปที่กำหนดเป้าหมายเป็น Android 8.0 ลักษณะการทำงานนี้ได้รับการแก้ไขแล้ว แอปจะได้รับเฉพาะสิทธิ์ที่ขอไว้อย่างชัดเจนเท่านั้น อย่างไรก็ตาม เมื่อผู้ใช้ให้สิทธิ์แก่แอป คำขอสิทธิ์ครั้งต่อๆ ไปทั้งหมดในกลุ่มสิทธิ์นั้นจะ ได้รับอนุญาตโดยอัตโนมัติ
ตัวอย่างเช่น สมมติว่าแอปแสดงทั้ง READ_EXTERNAL_STORAGE
และ WRITE_EXTERNAL_STORAGE
ในไฟล์ Manifest
แอปขอ READ_EXTERNAL_STORAGE
และผู้ใช้ให้สิทธิ์ หากแอปกำหนดเป้าหมายเป็น API ระดับ 25 หรือต่ำกว่า ระบบจะมอบสิทธิ์ WRITE_EXTERNAL_STORAGE
ให้ด้วยในขณะเดียวกัน เนื่องจากสิทธิ์ดังกล่าวอยู่ในกลุ่มสิทธิ์ STORAGE
เดียวกันและยังลงทะเบียนไว้ในไฟล์ Manifest ด้วย หากแอปกำหนดเป้าหมายเป็น Android 8.0 (API ระดับ 26) ระบบจะให้สิทธิ์ READ_EXTERNAL_STORAGE
เท่านั้น ณ ขณะนั้น แต่หากแอปขอ WRITE_EXTERNAL_STORAGE
ในภายหลัง ระบบจะให้สิทธิ์ดังกล่าวทันทีโดยไม่ต้องแจ้งให้ผู้ใช้ทราบ
สื่อ
- เฟรมเวิร์กสามารถลดระดับเสียงอัตโนมัติได้ด้วยตนเอง ในกรณีนี้ เมื่อแอปพลิเคชันอื่นขอโฟกัสด้วย
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
แอปพลิเคชันที่มีโฟกัสจะลดระดับเสียง แต่โดยปกติแล้วจะไม่ได้รับการเรียกกลับonAudioFocusChange()
และจะไม่เสียโฟกัสเสียง มี API ใหม่ให้ใช้เพื่อลบล้างลักษณะการทำงานนี้สำหรับแอปพลิเคชันที่ต้องหยุดชั่วคราวแทนการลดระดับเสียง - เมื่อผู้ใช้รับสาย สตรีมสื่อที่ใช้งานอยู่จะปิดเสียงตลอดระยะเวลาการโทร
- API ทั้งหมดที่เกี่ยวข้องกับเสียงควรใช้
AudioAttributes
แทนประเภทสตรีมเสียงเพื่ออธิบาย Use Case การเล่นเสียง ใช้ประเภทสตรีมเสียงเพื่อควบคุมระดับเสียงเท่านั้นต่อไป การใช้ประเภทสตรีมอื่นๆ จะยังคงใช้งานได้ (เช่น อาร์กิวเมนต์streamType
ไปยังตัวสร้างAudioTrack
ที่เลิกใช้งานแล้ว) แต่ระบบจะบันทึกการดำเนินการนี้ว่าเป็นข้อผิดพลาด - เมื่อใช้
AudioTrack
หากแอปพลิเคชันขอบัฟเฟอร์เสียงขนาดใหญ่พอ เฟรมเวิร์กจะพยายามใช้เอาต์พุตบัฟเฟอร์เชิงลึกหากมี - ใน Android 8.0 (API ระดับ 26) การจัดการเหตุการณ์ของปุ่มสื่อจะแตกต่างออกไปดังนี้
- การจัดการปุ่มสื่อในกิจกรรม UI ไม่ได้เปลี่ยนแปลงไป กิจกรรมที่ทำงานอยู่เบื้องหน้าจะยังคงมีความสำคัญในการจัดการเหตุการณ์ของปุ่มสื่อ
- หากกิจกรรมที่ทำงานอยู่เบื้องหน้าไม่จัดการเหตุการณ์ของปุ่มสื่อ ระบบจะส่งเหตุการณ์ไปยังแอปที่เล่นเสียงในเครื่องล่าสุด ระบบจะไม่พิจารณาสถานะใช้งาน สถานะการเล่น และสถานะเซสชันสื่อเมื่อพิจารณาว่าแอปใดจะได้รับเหตุการณ์ปุ่มสื่อ
- หากมีการปล่อยเซสชันสื่อของแอป ระบบจะส่งเหตุการณ์ปุ่มสื่อไปยัง
MediaButtonReceiver
ของแอป หากมี - สำหรับกรณีอื่นๆ ทั้งหมด ระบบจะทิ้งเหตุการณ์ปุ่มสื่อ
ไลบรารีที่มาพร้อมเครื่อง
ในแอปที่กำหนดเป้าหมายเป็น Android 8.0 (API ระดับ 26) ไลบรารีแบบเนทีฟจะไม่โหลดอีกต่อไปหากมีส่วนโหลดที่เขียนได้และเรียกใช้ได้ แอปบางแอปอาจหยุดทำงานเนื่องจากการเปลี่ยนแปลงนี้หากมีไลบรารีแบบเนทีฟที่มีกลุ่มการโหลดไม่ถูกต้อง การดำเนินการนี้เป็นมาตรการเพิ่มความแข็งแกร่งให้กับการรักษาความปลอดภัย
ดูข้อมูลเพิ่มเติมได้ที่ กลุ่มที่เขียนได้และกลุ่มที่เรียกใช้ได้
การเปลี่ยนแปลง linker จะเชื่อมโยงกับระดับ API ที่แอปกำหนดเป้าหมาย หากมีการเปลี่ยนแปลง Linker ในระดับ API เป้าหมาย แอปจะโหลดไลบรารีไม่ได้ หากคุณกําหนดเป้าหมายไปที่ระดับ API ต่ำกว่าระดับ API ที่การเปลี่ยนแปลง linker เกิดขึ้น แสดงว่า logcat จะแสดงคําเตือน
การจัดการคอลเล็กชัน
ใน Android 8.0 (API ระดับ 26) มีการใช้งาน Collections.sort()
ที่ด้านบนสุดของ List.sort()
ในทางกลับกัน List.sort()
ที่ใช้โดยค่าเริ่มต้นใน Android 7.x (API ระดับ 24 และ 25) จะเรียกว่า Collections.sort()
การเปลี่ยนแปลงนี้ช่วยให้ Collections.sort()
ใช้ข้อได้เปรียบของการใช้งาน List.sort()
ที่เพิ่มประสิทธิภาพได้ แต่มีข้อจำกัดต่อไปนี้
การใช้งาน
List.sort()
ต้องไม่เรียกCollections.sort()
เนื่องจากจะส่งผลให้สแต็กล้นเนื่องจากการเรียกซ้ำแบบไม่สิ้นสุด แต่หากต้องการลักษณะการทำงานเริ่มต้นในList
การใช้งาน คุณควรหลีกเลี่ยงการลบล้างsort()
หากคลาสหลักใช้
sort()
อย่างไม่เหมาะสม โดยทั่วไปแล้วการลบล้างList.sort()
ด้วยการติดตั้งใช้งานที่สร้างขึ้นจากList.toArray()
,Arrays.sort()
และListIterator.set()
นั้นไม่มีปัญหา เช่น@Override public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } }
ในกรณีส่วนใหญ่ คุณสามารถลบล้าง
List.sort()
ด้วยการใช้งานที่มอบสิทธิ์ให้กับการใช้งานเริ่มต้นที่แตกต่างกัน ทั้งนี้ขึ้นอยู่กับระดับ API เช่น@Override public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } }
หากคุณทําแบบหลังเพียงเพราะต้องการมีเมธอด
sort()
ที่พร้อมใช้งานในทุกระดับ API ให้ลองตั้งชื่อที่ไม่ซ้ำกัน เช่นsortCompat()
แทนการลบล้างsort()
-
ตอนนี้
Collections.sort()
จะนับเป็นการแก้ไขโครงสร้างในการใช้งานลิสต์ที่เรียกsort()
ตัวอย่างเช่น ในแพลตฟอร์มเวอร์ชันก่อน Android 8.0 (API ระดับ 26) การวนซ้ำArrayList
และเรียกใช้sort()
ในระหว่างการวนซ้ำจะทำให้เกิดConcurrentModificationException
หากการเรียงลำดับเสร็จสิ้นแล้วโดยการเรียกใช้List.sort()
Collections.sort()
ไม่ได้ส่งข้อยกเว้นการเปลี่ยนแปลงนี้ทําให้ลักษณะการทํางานของแพลตฟอร์มสอดคล้องกันมากขึ้น ตอนนี้ทั้ง 2 วิธีจะให้ผลลัพธ์เป็น
ConcurrentModificationException
ลักษณะการโหลดคลาส
Android 8.0 (API ระดับ 26) จะตรวจสอบว่าตัวโหลดคลาสไม่ละเมิดสมมติฐานของรันไทม์เมื่อโหลดคลาสใหม่ ระบบจะดำเนินการตรวจสอบเหล่านี้ไม่ว่าจะมีการอ้างอิงคลาสจาก Java (จาก forName()
), บิตโค้ด Dalvik หรือ JNI ก็ตาม แพลตฟอร์มจะไม่สกัดกั้นการเรียกใช้โดยตรงจาก Java ไปยังเมธอด loadClass()
และไม่ได้ตรวจสอบผลลัพธ์ของการเรียกดังกล่าว ลักษณะการทํางานนี้ไม่ควรส่งผลต่อการทำงานของโปรแกรมโหลดคลาสที่ทำงานอย่างถูกต้อง
แพลตฟอร์มจะตรวจสอบว่าตัวบ่งชี้ของคลาสที่ตัวโหลดคลาสแสดงผลตรงกับตัวบ่งชี้ที่คาดไว้ หากตัวระบุที่แสดงผลไม่ตรงกัน แพลตฟอร์มจะแสดงข้อผิดพลาด NoClassDefFoundError
และจัดเก็บข้อความโดยละเอียดที่ระบุถึงความคลาดเคลื่อนไว้ในข้อยกเว้น
นอกจากนี้ แพลตฟอร์มจะตรวจสอบว่าตัวบ่งชี้ของคลาสที่ขอนั้นถูกต้องด้วย การตรวจสอบนี้จะตรวจจับการเรียกใช้ JNI ที่โหลดคลาสโดยอ้อม เช่น GetFieldID()
ซึ่งส่งผ่านข้อบ่งชี้ที่ไม่ถูกต้องไปยังคลาสเหล่านั้น ตัวอย่างเช่น ไม่พบช่องที่มีลายเซ็น java/lang/String
เนื่องจากลายเซ็นดังกล่าวไม่ถูกต้อง ช่องนี้ควรเป็น Ljava/lang/String;
ซึ่งแตกต่างจากการเรียก JNI ไปยัง FindClass()
โดยที่ java/lang/String
เป็นชื่อที่สมบูรณ์ในตัวเองที่ถูกต้อง
Android 8.0 (API ระดับ 26) ไม่รองรับการที่ตัวโหลดคลาสหลายตัวพยายามกำหนดคลาสโดยใช้ออบเจ็กต์ DexFile เดียวกัน การพยายามดำเนินการดังกล่าวจะทำให้รันไทม์ Android แสดงInternalError
ข้อผิดพลาดพร้อมข้อความ "พยายามลงทะเบียนไฟล์ dex <filename>
ด้วยตัวโหลดคลาสหลายรายการ"
DexFile API เลิกใช้งานแล้ว และเราขอแนะนําอย่างยิ่งให้คุณใช้คลาสโหลดเดอร์ของแพลตฟอร์มอย่างใดอย่างหนึ่ง ซึ่งรวมถึง PathClassLoader
หรือ BaseDexClassLoader
แทน
หมายเหตุ: คุณสามารถสร้างตัวโหลดคลาสได้หลายรายการซึ่งอ้างอิงคอนเทนเนอร์ไฟล์ APK หรือ JAR เดียวกันจากระบบไฟล์ ซึ่งโดยทั่วไปแล้วจะไม่ทำให้เกิดค่าใช้จ่ายด้านหน่วยความจำมากนัก หากมีการเก็บไฟล์ DEX ในคอนเทนเนอร์แทนการบีบอัด แพลตฟอร์มจะดำเนินการ mmap
กับไฟล์เหล่านั้นได้โดยไม่ต้องดึงข้อมูลโดยตรง อย่างไรก็ตาม หากแพลตฟอร์มต้องดึงไฟล์ DEX ออกจากคอนเทนเนอร์ การอ้างอิงไฟล์ DEX ในลักษณะนี้อาจใช้หน่วยความจำจำนวนมาก
ใน Android ระบบจะถือว่าตัวโหลดคลาสทั้งหมดทำงานแบบขนานได้ เมื่อหลายเธรดแข่งกันโหลดคลาสเดียวกันด้วยคลาสโหลดเดอร์เดียวกัน เธรดแรกที่ดำเนินการเสร็จสมบูรณ์จะเป็นผู้ชนะ และระบบจะใช้ผลลัพธ์นั้นกับเธรดอื่นๆ ลักษณะการทำงานนี้จะแสดงขึ้นไม่ว่าตัวโหลดคลาสจะแสดงผลคลาสเดียวกัน คลาสอื่น หรือแสดงข้อยกเว้น แพลตฟอร์มจะไม่สนใจข้อยกเว้นดังกล่าว
ข้อควรระวัง: ในแพลตฟอร์มเวอร์ชันที่ต่ำกว่า Android 8.0 (ระดับ API 26) การละเมิดข้อสมมติเหล่านี้อาจทําให้ต้องกําหนดคลาสเดียวกันหลายครั้ง กองข้อมูลเสียหายเนื่องจากความสับสนของคลาส และผลที่ไม่พึงประสงค์อื่นๆ