ฉันจะป้องกันไม่ให้ Android จับภาพหน้าจอเมื่อแอปของฉันไปที่พื้นหลังได้อย่างไร


146

แอพที่ฉันกำลังสร้างอยู่นั้นมีข้อกำหนดว่าแอพต้องป้องกันไม่ให้ระบบปฏิบัติการจับภาพหน้าจอของแอพเมื่อมันถูกส่งไปยังพื้นหลังเพื่อเหตุผลด้านความปลอดภัย วิธีนี้จะไม่สามารถเห็นหน้าจอที่ใช้งานล่าสุดเมื่อสลับระหว่างแอป

ฉันวางแผนที่จะวางฟังก์ชั่นนี้ไว้ในวิธีการ onPause ของแอปพลิเคชันคลาส แต่ก่อนอื่นฉันต้องค้นหาวิธีที่ฉันสามารถใช้ฟังก์ชันนี้ได้

มีใครออกไปข้างนอกนั่นมีเงื่อนงำที่จะแก้ไขปัญหานี้ได้อย่างไร

คำตอบ:


264

ลองFLAG_SECURE:

public class FlagSecureTestActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                         WindowManager.LayoutParams.FLAG_SECURE);

    setContentView(R.layout.main);
  }
}

วิธีนี้ช่วยป้องกันภาพหน้าจอด้วยตนเองและภาพหน้าจออัตโนมัติจากประวัติงานล่าสุดของ ICS นอกจากนี้ยังป้องกันการบันทึกหน้าจอ (เช่นแอปที่ใช้ API การฉายสื่อ)

ปรับปรุง : มันยังยึดติดกับ Now On Tap หรือผู้ช่วยอื่น ๆ ใน Android 6.0; พวกเขาจะไม่สามารถเข้าถึงรายละเอียดของวิดเจ็ตและคอนเทนเนอร์ใน UI ของคุณหากผู้ใช้นำผู้ช่วยขึ้นมา

อัปเดต # 2 : อย่างไรก็ตามทุกอย่างในกิจกรรมจะไม่ได้รับการคุ้มครอง ใด ๆ หน้าต่างป๊อปอัพ - Dialog, Spinner, AutoCompleteTextViewการกระทำบาร์ล้น ฯลฯ - จะไม่ปลอดภัย คุณสามารถแก้ไขDialogปัญหาโดยการเรียกเกี่ยวกับมันและการตั้งค่าgetWindow() FLAG_SECUREที่เหลือ ... รับเล่ห์เหลี่ยม ดูโพสต์บล็อกนี้สำหรับข้อมูลเพิ่มเติม


6
@ Dany's: จริงๆแล้วมันมีทุกอย่างที่เกี่ยวข้องกับคำถาม ฉันเพิ่งทดสอบมันบน Nexus S (4.0.3) และทำงานได้ตามที่คาดหวัง - ภาพหน้าจอของงานล่าสุดถูกระงับ คุณยังคงเห็นชื่อแอปพลิเคชันและไอคอน แต่ภาพหน้าจอเป็นสีดำ คุณสามารถลองใช้กับฮาร์ดแวร์ ICS ได้
CommonsWare

2
@ StingRay5: FLAG_SECUREมีอยู่ตั้งแต่เริ่มต้น - มันเพิ่งมีความหมาย จำกัด จนกระทั่งเมื่อไม่นานมานี้
CommonsWare

1
ที่น่าสนใจที่จะทราบว่ามีวิธีการที่เรียกว่า onCreateThumbnail ni วงจรชีวิตของกิจกรรม แต่มันไม่เคยใช้
Snicolas

2
@PankajKumar: หาก "รหัสที่จะถ่ายหน้าจอ" ที่คุณเขียนคือคลาสสิก "เคล็ดลับการจับ framebuffer เป็นรูท" FLAG_SECUREจะไม่ป้องกันสิ่งนั้นเพราะมันอยู่ในระดับต่ำเกินไป ในทำนองเดียวกันถ้าคุณเอาลำดับชั้นเครื่องมือของคุณเองและก็วาดไปBitmap-backed Canvas, FLAG_SECUREอาจจะไม่ป้องกันที่เป็นคุณจะพาหน้าจอของคุณเองของเครื่องมือของคุณเองและดังนั้นจึงสันนิษฐานว่าต้องการ "ความปลอดภัย" คนที่อยู่ในนั้น FLAG_SECUREมีไว้สำหรับภาพหน้าจอของระบบเช่นภาพขนาดย่องานล่าสุด
CommonsWare

2
คำตอบที่ยอดเยี่ยมและเรียบง่าย! ฉันสงสัยว่าเพราะเหตุใดแอปอย่างSnapchat จึงไม่ใช้สิ่งนี้เพื่อป้องกันไม่ให้มีคนจับภาพหน้าจอของภาพที่ส่ง
Shobhit Puri

78

ระวังเกี่ยวกับการใช้ WindowManager.LayoutParams.FLAG_SECURE ในอุปกรณ์บางอย่าง (ตรวจสอบกับ Samsung Galaxy ACE เช่น GT-S5830) สิ่งนี้จะทำให้มุมมองดังกล่าวมีสัญญาณรบกวน ดูเหมือนว่าบั๊กเฉพาะของ Samsung ฉันขอแนะนำดังต่อไปนี้:

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}

นี่คือลักษณะของหน้าจอที่มีสัญญาณรบกวน:

ภาพหน้าจอสัญญาณรบกวน

สิ่งนี้ทำงานได้อย่างถูกต้องบนโทรศัพท์ ICS Samsung ดังนั้นฉันคิดว่าปัญหาจะถูกแยกไปยังอุปกรณ์ Gingerbread (หรือเก่ากว่า)


8
คุณพูดถูกแล้วเราเจอปัญหานี้และแน่นอนว่าจำเป็นต้องตรวจสอบระดับ API ที่จริงแล้วลืมโพสต์สิ่งนี้ดังนั้นขอบคุณที่นำมันขึ้นมาอีกครั้ง :)
StingRay5

มันเกิดขึ้นกับ Samsung Gio (Gingerbread) แต่บน Froyo มันโอเค - ดังนั้นมันจะเกิดขึ้นเฉพาะในวันที่ 2.3
pixel

เราสังเกตเห็นปัญหานี้เช่นกัน คุณสามารถตรวจสอบในเครื่องจำลองบนอุปกรณ์ Gingerbread
twaddington

ฉันสามารถยืนยันได้ว่าปัญหานี้ปรากฏขึ้นบนอุปกรณ์ Samsung Gingerbread
Ernir Erlingsson

7
แม้ในเวอร์ชัน Android ที่ใหม่กว่า FLAG_SECURE อาจเป็นปัญหาได้: ใน Android 4.3 FLAG_SECURE ทำให้เกิดปัญหาภาพเคลื่อนไหวในการเคลื่อนไหวหน้าจอหมุนดูcode.google.com/p/android/issues/detail?id=58632 - สิ่งนี้ได้รับการแก้ไขแล้วบน Android 4.4
Oliver

13

วิธีการแก้ปัญหาที่ให้โดย CommonsWare ยังคงใช้ได้ใน Lollipop

เพียงแค่ทราบถ้าคุณต้องการที่จะยังคงไม่เห็นภาพรวมในรายการที่ผ่านมาสำหรับทั้งแอปทุกกิจกรรมการดำเนินการควรระบุในonCreate()วิธีการที่ธงgetWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); ก่อนsetContentView();

มิฉะนั้นสแน็ปช็อตในรายการล่าสุดจะแสดงกิจกรรมแรกโดยไม่ต้องตั้งค่าสถานะหากผู้ใช้นำทางผ่าน


1
ในแอพของฉันฉันมีฟังก์ชันการตั้งค่า / การล้าง FLAG_SECURE ตามการตั้งค่าของผู้ใช้ มันทำงานได้ดีจนถึง KITKAT และหน้าจอสีดำสามารถเห็นได้ใน task switcher ใน Lollipop ภาพรวมแสดงภาพรวมสุดท้ายของแอพของฉันเวลาที่ไม่ได้ตั้งค่า FLAG_SECURE (ล้างข้อมูล)
r.bhardwaj

@ r.bhardwaj ฉันคิดว่าเราไม่สามารถทำอะไรได้มากในกรณีนั้น แต่คุณสามารถให้คำแนะนำผู้ใช้ว่าการเปลี่ยนแปลงนั้นต้องเริ่มต้นแอปใหม่เพื่อให้มีผลอย่างเต็มที่ ;-) และคุณก็ทำเสร็จแล้ว
Davideas

1
ใครพบวิธีขยายมุมมองที่กำหนดเองก่อนที่จะถ่ายภาพสแนปช็อตจึงไม่ใช่แค่หน้าจอสีดำ ฉันได้ลองขยายมุมมองตัวจัดการหน้าต่างใน onPause แต่ดูเหมือนว่ามันจะสายเกินไป
user1064249

สวัสดี @ user1064249 คุณพบวิธีการแก้ปัญหาใด ๆ ? ฉันต้องการขยายมุมมองตัวเรียกดูก่อนที่ระบบปฏิบัติการจะจับภาพหน้าจอ
Alexiscanny

1

นี่คือทางออกสำหรับการซ่อนเนื้อหาของแอพด้วยการปิดบังหน้าจอเมื่อแอพถูกใส่เข้าไปในพื้นหลัง นี่ไม่ได้ใช้เทคนิค FLAG_SECURE ฉันแค่แทนที่เมธอด onPause และ onResume ของหน้าจอและปรับเปลี่ยนมุมมองเพื่อแสดงอันที่ครอบคลุมทุกอย่างที่ด้านหลัง

https://stackoverflow.com/a/52976001/6686912


0
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE);

มันใช้งานได้สำหรับฉันมันป้องกันไม่ให้ถ่ายภาพหน้าจอและแอปพลิเคชันบันทึก inbuilt หรือบุคคลที่สามใด ๆ จากหน้าจอบันทึก


0

สิ่งนี้ใช้ได้สำหรับฉันหลังจากเพิ่มบรรทัดเหล่านี้ใน onCreate ก่อน setContentView ของทุกกิจกรรม

getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,     
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_notification);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.