Guideline 2.5.4: Apple ปฏิเสธโหมดเบื้องหลัง แก้อย่างไร
โดย Mehdi Azizi
เผยแพร่เมื่อ , 9 นาที
Guideline 2.5.4: Apple ปฏิเสธโหมดเบื้องหลังที่ประกาศไว้แต่ไม่มีฟีเจอร์ใช้ ให้ลบคีย์ออก หรือแสดงเสียง ตำแหน่ง หรือการโทรให้ผู้ตรวจดู
Guideline 2.5.4 จำกัดให้ใช้โหมดเบื้องหลัง (background mode) ได้ตามจุดประสงค์ของมันเท่านั้น คือ เสียง ตำแหน่ง การโทร VoIP การทำงานให้เสร็จ และการแจ้งเตือนในเครื่อง คุณจะโดนปฏิเสธเมื่อ Info.plist ของคุณประกาศโหมดใดโหมดหนึ่งไว้ แต่ผู้ตรวจหาฟีเจอร์ที่ต้องใช้โหมดนั้นไม่เจอ ถ้าไม่มีอะไรใช้คีย์นั้น ให้ลบออก ถ้ามี ให้แสดงฟีเจอร์นั้นให้ผู้ตรวจเห็นภายในสามสิบวินาที
ผมเผยแพร่แอป iOS ของตัวเองด้วย Expo แอป Solys นาฬิกาปลุกที่มีมินิเกมของผม ประกาศโหมด audio ไว้ ผมเคยลบออก แล้วก็ใส่กลับเข้าไปด้วยเหตุผลอื่น คู่มือนี้อ้างอิงจากข้อความของ Apple, กรณีถูกปฏิเสธที่นักพัฒนาคนอื่นเผยแพร่ไว้ และโปรเจกต์ของผมเอง ถ้าอยากเห็นภาพรวมของเหตุผลที่โดนปฏิเสธทั้งหมด อ่านทำไม Apple ถึงปฏิเสธแอป
Guideline 2.5.4 พูดว่าอะไร?
กฎนี้มีแค่ประโยคเดียว อยู่ในหมวด 2 "Performance" ส่วน 2.5 "Software Requirements" ของ App Review Guidelines: "Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc."
พูดง่าย ๆ คือ บริการเบื้องหลังใช้ได้เฉพาะกับสิ่งที่มันถูกสร้างมาเพื่อทำ จึงเป็นที่มาของหัวข้อ "Guideline 2.5.4 - Performance - Software Requirements"
โดยปกติ แอปที่ถูกสลับไปอยู่เบื้องหลังจะถูกพักการทำงาน ถ้าจะให้ทำงานต่อ แอปต้องประกาศโหมดหนึ่งโหมดหรือมากกว่าในคีย์ UIBackgroundModes ของ Info.plist เอกสารของ Apple เรื่องโหมดเบื้องหลัง ขอให้ใช้อย่างประหยัดเพราะเรื่องแบตเตอรี่ และให้เลือกวิธีอื่นถ้ามี ทุกโหมดที่ประกาศคือคำสัญญาที่ผู้ตรวจตรวจสอบได้
โหมดเบื้องหลังและการใช้งานตามจุดประสงค์
| โหมด | คีย์ | การใช้งานตามจุดประสงค์ |
|---|---|---|
| Audio, AirPlay, PiP | audio | เสียงที่ได้ยินขณะอยู่เบื้องหลัง |
| ตำแหน่ง | location | ติดตามตำแหน่งต่อเนื่อง |
| Voice over IP | voip | การโทรผ่าน CallKit |
| ดึงข้อมูล | fetch | เนื้อหาจากเครือข่ายเป็นประจำ |
| ประมวลผล | processing | งานที่ตั้งเวลาไว้ |
| การแจ้งเตือนระยะไกล | remote-notification | Push แจ้งเนื้อหาใหม่ |
ตารางนี้สรุปจากหน้าของ Apple ในกรณีถูกปฏิเสธที่โพสต์ในฟอรัม audio, location และ voip เจอบ่อยที่สุด
ข้อความปฏิเสธ 2.5.4 หมายความว่าอะไร?
ข้อความจะระบุชื่อโหมดที่มีปัญหา นี่คือสองตัวอย่างที่นักพัฒนาโพสต์ในฟอรัมของ Apple:
- Audio: "Your app still declares support for audio in the UIBackgroundModes key in your Info.plist but did not include features that require persistent audio." ข้อความต่อมาอธิบายว่าคีย์
audioมีไว้สำหรับแอปที่เล่นเนื้อหาให้ได้ยินขณะอยู่เบื้องหลัง เช่น เครื่องเล่นเพลง และเสนอทางออกสองทาง คือเพิ่มเนื้อหาแบบนั้น หรือลบคีย์ออก (เธรดในฟอรัม) - ตำแหน่ง: ในเธรดเดือนธันวาคม 2024 Apple ไม่พบฟีเจอร์อื่นนอกจากการติดตามพนักงานที่ต้องใช้ตำแหน่งตลอดเวลา และเขียนว่าการใช้งานแค่นี้อย่างเดียวไม่เหมาะสม
ความเห็นของผม: ผู้ตรวจไม่ได้อ่านโค้ดของคุณ เขามองหาฟีเจอร์ เขาต้องเปิดฟีเจอร์นั้นได้ สลับแอปไปเบื้องหลัง แล้วเห็นว่ามันยังทำงานต่อ
กรณีกลับกันก็มี ในเธรดเดือนพฤษภาคม 2026 แอปอ่านออกเสียงที่ใช้โหมด audio จริง ๆ ถูกปฏิเสธหลายครั้ง เพราะผู้ตรวจทำให้เสียงดังขึ้นมาไม่ได้ นักพัฒนาอีกคนเขียนไว้ในเธรดว่า เขาคิดว่าวิดีโอที่แนบไปช่วยปลดล็อกกรณีของเขา นี่เป็นแค่คำบอกเล่า ไม่ใช่กฎของ Apple
คีย์มาจากไหน ในเมื่อคุณไม่ได้ใส่เอง?
ใน Expo ปลั๊กอินคอนฟิกคือตัวที่เขียนค่าลงใน Info.plist ตอน prebuild โหมดเบื้องหลังจึงหลุดเข้าไปในไบนารีได้โดยที่คุณไม่ได้ตั้งใจ
ปลั๊กอิน expo-audio กับค่าเริ่มต้น
เอกสารของ expo-audio ระบุไว้ว่า ตัวเลือก enableBackgroundPlayback มีค่าเริ่มต้นเป็น true และบน iOS จะเพิ่มโหมด audio เข้าไป แค่ประกาศปลั๊กอินแบบสั้น "expo-audio" ก็เท่ากับประกาศโหมดนี้แล้ว
นี่คือสิ่งที่ผมเจอตอนตรวจ TradaZen ก่อนส่งครั้งแรก มีแค่เสียงสั้น ๆ ของ UI ตอนแอปอยู่หน้าจอ แต่ปลั๊กอินถูกประกาศแบบสั้น วิธีแก้อยู่ใน app.json:
{
"expo": {
"plugins": [["expo-audio", { "enableBackgroundPlayback": false }]]
}
}
แพ็กเกจอื่นก็เพิ่มโหมดในแบบของมัน ตัวเลือก isIosBackgroundLocationEnabled ของ expo-location จะเพิ่ม location เฉพาะเมื่อคุณเปิดใช้ ส่วน expo-background-task จะเพิ่ม processing ตอน prebuild ทันทีที่ติดตั้ง
โฟลเดอร์ ios/ ที่เก็บคีย์เก่าไว้
กับดักที่สอง ผมเจอเองกับ Solys เมื่อกรกฎาคม 2026 ผมลบ audio ออกจาก app.json แล้ว แต่คีย์ยังค้างอยู่ใน ios/Solys/Info.plist ที่สร้างไว้ก่อนหน้า การ prebuild โดยไม่ใส่ --clean จะแก้ไขโปรเจกต์เดิมแทนที่จะสร้างใหม่ และปลั๊กอินเพิ่มคีย์ได้แต่ไม่เคยลบออก ถ้า build ในเครื่องก็จะพาคีย์นั้นติดไปด้วย ส่วน EAS build บนคลาวด์จะเริ่มจาก prebuild ใหม่ถ้า ios/ ถูก git ignore ไว้ ซึ่งเป็นกรณีของผม
ก่อน build ทุกครั้ง ผมเช็กว่าอะไรจะถูกส่งไปจริง ๆ:
npx expo config --type introspect --json | grep -o '"UIBackgroundModes":\[[^]]*\]'
npx expo prebuild --clean --platform ios
คำสั่งแรกแสดงโหมดที่ prebuild จะเขียนลงใน Info.plist คำสั่งที่สองสร้างโปรเจกต์ native ใหม่สำหรับ build ในเครื่อง โดยลบโฟลเดอร์ ios/ ทิ้ง บน Solys คำสั่งแรกแสดง "UIBackgroundModes":["audio"] บน TradaZen ไม่แสดงอะไร ทั้งสองแบบเป็นสิ่งที่ผมตั้งใจ
การเพิ่มหรือลบโหมดคือการแก้ Info.plist ซึ่งก็คือการแก้ไบนารี คุณต้อง build ใหม่ อัปเดตทางไกลอย่างเดียวไม่พอ เอกสารของ EAS Update จัดการเปลี่ยนแปลงแบบนี้ไว้ในกลุ่มที่ต้องใช้ไบนารีใหม่ เหมือนกรณี ITMS-90683
Solys: ประกาศโหมด audio ไว้ โดยมีเหตุผลจริง
Solys เป็นนาฬิกาปลุก แต่โหมด audio ไม่ได้มีไว้ให้เสียงปลุกดัง เสียงปลุกทำงานผ่าน AlarmKit บริการนาฬิกาปลุกของ Apple ที่มีตั้งแต่ iOS 26 (เอกสาร AlarmKit) ระบบเป็นตัวส่งเสียง แม้อยู่ในโหมดเงียบ ไม่ใช่ตัวแอป
ประวัติของคีย์นี้ เพราะเหตุผลสำคัญกว่าบรรทัดโค้ด:
- ปลายกรกฎาคม 2026 ผมลบมันออก ไม่มีอะไรเล่นเสียงอยู่เบื้องหลังเลย เสียงประกอบมินิเกมเล่นเฉพาะตอนแอปอยู่หน้าจอ และเสียงปลุกก็ไม่ได้พึ่งตัวแอป
- สองวันต่อมา ผมใส่มันกลับเข้าไป พร้อมฟีเจอร์ฟังเสียงตอนกลางคืน ตัวเลือกนี้บันทึกเสียงระหว่างคืนของคุณด้วยไมโครโฟน แล้ววิเคราะห์บน iPhone การบันทึกต้องทำต่อตอนล็อกหน้าจอ และเอกสารของ expo-audio ระบุว่าตัวเลือกบันทึกเสียงเบื้องหลังก็เพิ่มโหมด
audioเช่นกัน
เหตุผลเปลี่ยนไปคนละแบบ: โหมดนี้ใช้เพื่อบันทึก ไม่ใช่เพื่อเล่น มีมาตรการป้องกันสามข้อที่เห็นได้ในแอป:
- การฟังเป็นตัวเลือกที่ปิดไว้เป็นค่าเริ่มต้น เปิดได้จากการตั้งค่าหรือจากกิจวัตรตอนเย็น
- มีหน้าขอความยินยอมของตัวเอง ตามที่กฎ 2.5.14 กำหนดไว้สำหรับการบันทึกทุกชนิด และไม่มีข้อมูลใดออกจากโทรศัพท์
- ไมโครโฟนจะปิดสิบนาทีก่อนเวลาปลุก เพื่อไม่ให้การฟังกับเสียงปลุกรบกวนกัน
ผมรับประกันไม่ได้ว่าผู้ตรวจจะยอมรับการประกาศนี้ทุกครั้ง แต่ผมบอกได้ว่าแต่ละส่วนมีไว้ทำอะไร และดูได้ที่ไหน
นาฬิกาปลุกที่เคยทำให้แอปตื่นอยู่ตลอด
ก่อนมี AlarmKit แอปนาฬิกาปลุกจากภายนอกไม่สามารถดังได้เหมือนนาฬิกาปลุกของ Apple บางไลบรารีจึงทำให้แอปตื่นอยู่ตลอด เอกสารของแพ็กเกจ Flutter alarm2 อธิบายถึงเครื่องเล่นเสียงแบบเงียบที่ทำงานไปจนถึงเวลาปลุก แต่เสียงเงียบไม่ได้ทำให้ได้ยินอะไรเลย ตั้งแต่ iOS 26 AlarmKit ทำให้วิธีอ้อมนี้ไม่จำเป็นอีกต่อไป
เก็บหรือลบโหมด: ตารางช่วยตัดสินใจ
| สถานการณ์ของคุณ | ควรทำอะไร |
|---|---|
| เสียงสั้น ๆ ตอนแอปอยู่หน้าจอ | ลบ audio |
| เพลงหรือหนังสือเสียง | เก็บไว้ และแสดงให้เห็น |
| บันทึกเสียงนาน ๆ | เก็บไว้ + ขอความยินยอม |
| นาฬิกาปลุกหรือตัวจับเวลา | AlarmKit (iOS 26) |
| ใช้ตำแหน่งเป็นครั้งคราว | Significant location changes |
| ซิงก์ที่ไม่เร่งด่วน | fetch หรือ processing |
| โทรเสียงหรือวิดีโอ | voip กับ CallKit |
สำหรับตำแหน่ง หน้าของ Apple แนะนำบริการ significant location changes เป็นทางเลือกแทนโหมด location
ข้อย่อยอื่นของ 2.5: 2.5.1 และ 2.5.2
2.5.1: API สาธารณะ และใช้ framework ให้ถูกที่
"Apps may only use public APIs and must run on the currently shipping OS." แอปต้องใช้เฉพาะ API สาธารณะ ทำงานบนระบบเวอร์ชันปัจจุบัน และเลิกใช้สิ่งที่ถูก deprecate เหมือนกับ 2.5.4 แต่ละ framework ต้องใช้ตามจุดประสงค์และระบุไว้ในคำอธิบาย เช่น HealthKit สำหรับสุขภาพ HomeKit สำหรับบ้านอัจฉริยะ ถ้าไลบรารีไหนเรียก API ส่วนตัว แอปของคุณคือตัวที่โดนปฏิเสธ
2.5.2: ห้ามดาวน์โหลดโค้ดที่เปลี่ยนแอป
แอปต้องสมบูรณ์ในตัวแพ็กเกจของมัน ห้าม "download, install, or execute code which introduces or changes features or functionality of the app" มีแค่แอปการศึกษาที่สอนเขียนโค้ดที่ได้รับข้อยกเว้นแบบจำกัด โดยโค้ดต้องเปิดให้ผู้ใช้เห็นและแก้ไขได้ทั้งหมด
ใน Expo ประเด็นนี้เกี่ยวกับ EAS Update ซึ่งเอกสารย้ำว่าอัปเดตต้องเป็นไปตามกฎของ App Store ใช้อัปเดตทางไกลเพื่อแก้บั๊กเท่านั้น อย่าใช้ส่งฟีเจอร์ที่ผู้ตรวจไม่เคยเห็น การแก้ไขที่เกี่ยวกับการรีวิวต้องผ่าน build ใหม่ ตามที่ผมอธิบายในคู่มือ guideline 2.1
จะตอบการปฏิเสธ 2.5.4 อย่างไร?
การสนทนาเกิดขึ้นในส่วน App Review ของแอปคุณ ที่คุณตอบกลับข้อความของ App Review มีสองกรณี:
- โหมดไม่ได้ใช้ทำอะไร: ลบออก build ใหม่ ตรวจผลจาก introspection แล้วตอบกลับสองประโยค
- โหมดใช้กับฟีเจอร์จริง: ตอบพร้อมขั้นตอนที่ชัดเจนและวิดีโอสั้น ๆ แล้วนำข้อความเดียวกันไปใส่ใน review notes ของทุกเวอร์ชัน
นี่คือแม่แบบที่ผมจะใช้ ปรับตามแอปของคุณ (ลบประโยคเรื่องนาฬิกาปลุกออกถ้าแอปของคุณไม่มี):
Hello,
The "audio" background mode is used only by [feature], an
optional feature that [records / plays] audio while the
device is locked. It is off by default.
How to test:
1. Open [screen] and turn on [feature].
2. Accept the microphone permission if asked.
3. Tap [button], then lock the device.
[What the reviewer will hear or see.]
Our alarm does not use this mode: it is scheduled with
AlarmKit and rings through the system.
Attached: a short screen recording of these steps.
Best regards,
เช็กลิสต์ 2.5.4 ก่อนส่ง
- ผล introspection ของ Expo แสดงเฉพาะโหมดที่ตั้งใจ และคุณบอกได้ว่าแต่ละโหมดใช้กับฟีเจอร์ไหน
- ไม่มีปลั๊กอินที่ประกาศแบบสั้น ถ้ามันเพิ่มโหมดเป็นค่าเริ่มต้น เช่น expo-audio
- โฟลเดอร์
ios/ในเครื่องไม่มีคีย์เก่าค้างอยู่ หรือคุณ build จาก prebuild ที่สะอาด - ฟีเจอร์เปิดใช้ได้เร็ว ไม่มีการตั้งค่าซ่อนอยู่ และ review notes บอกว่าแต่ละโหมดใช้ทำอะไรและทดสอบอย่างไร
- การบันทึกเสียงทุกชนิดต้องขอความยินยอมอย่างชัดเจน และแสดงสัญลักษณ์ให้เห็น กฎเรื่องการขอสิทธิ์อยู่ในคู่มือ guideline 5.1.1
- สำหรับนาฬิกาปลุก เสียงปลุกต้องผ่าน AlarmKit ไม่ใช่เสียงที่เล่นจากแอป
ตรวจแอปของคุณก่อนส่ง
Review Kit รวมเช็กลิสต์ก่อนส่งของผม แม่แบบโน้ตสำหรับผู้ตรวจ และ skill ของ Claude Code ที่ช่วยตรวจโปรเจกต์ของคุณ ถ้าอยากให้คนช่วยดู จองเวลาหนึ่งชั่วโมงกับผม เราจะอ่านข้อความจาก Apple และ Info.plist ของคุณด้วยกันผ่านวิดีโอคอล ขั้นตอนทั้งหมดอยู่ที่หน้าแอปถูก Apple ปฏิเสธ
กำลังเตรียมปล่อยแอปแรกอยู่ใช่ไหม? ทำแบบประเมินฟรี มันจะเรียงลำดับขั้นตอนให้ และส่งเช็กลิสต์กันโดน Apple ปฏิเสธของผมให้คุณ
ไม่มีใครรับประกันได้ว่า Apple จะยอมรับแอปของคุณ แต่โหมดเบื้องหลังที่มีเหตุผลชัดเจน อธิบายได้ภายในสามสิบวินาที
คำถามที่พบบ่อย
"Guideline 2.5.4 - Performance - Software Requirements" หมายความว่าอะไร?
คือหัวข้อการปฏิเสธเมื่อ Apple เห็นว่าโหมดเบื้องหลังใน Info.plist ของคุณไม่ได้ใช้ตามจุดประสงค์ ข้อความจะระบุชื่อโหมด และเสนอให้คุณแสดงฟีเจอร์ที่ใช้มัน หรือลบคีย์ออก
ต้อง build ใหม่หลังโดนปฏิเสธ 2.5.4 ไหม?
ถ้าคุณลบหรือแก้โหมด ต้อง เพราะคีย์อยู่ใน Info.plist ซึ่งอยู่ในไบนารี ถ้าโหมดมีเหตุผลรองรับ การตอบกลับพร้อมขั้นตอนที่ชัดเจนและวิดีโออาจเพียงพอ
เก็บโหมด audio ไว้สำหรับเสียง UI ไม่กี่เสียงได้ไหม?
ไม่ได้ เสียงสั้น ๆ ที่เล่นตอนแอปอยู่หน้าจอไม่จำเป็นต้องใช้โหมดนี้ ใน Expo ให้ตั้ง enableBackgroundPlayback เป็น false ในปลั๊กอิน expo-audio
แอปนาฬิกาปลุกต้องใช้โหมด audio ไหม?
ไม่ต้องสำหรับการปลุก ถ้าใช้ AlarmKit ที่มีตั้งแต่ iOS 26 เพราะระบบเป็นตัวเล่นเสียงปลุก บน Solys โหมด audio ใช้กับฟีเจอร์ฟังเสียงตอนกลางคืน ที่บันทึกเสียงขณะล็อกหน้าจอ
ทำไม Apple อ้าง 2.5.4 ทั้งที่ผมไม่ได้ประกาศอะไรเลย?
ปลั๊กอินอาจทำให้แทนคุณ expo-audio เพิ่มโหมด audio เป็นค่าเริ่มต้น และโฟลเดอร์ ios/ เก่าอาจเก็บคีย์ที่คุณลบออกจากคอนฟิกไปแล้ว ตรวจสอบด้วย npx expo config --type introspect

