การควบคุมภาพหน้าจอในตัวสลับการทำงานหลายอย่างของ iOS 7


98

ฉันพยายามหาข้อมูลบางอย่างเกี่ยวกับตัวสลับมัลติทาสก์ใหม่ใน iOS 7 และโดยเฉพาะอย่างยิ่งภาพหน้าจอที่ระบบปฏิบัติการใช้เมื่อแอปเข้าสู่โหมดไฮเบอร์เนต

ป้อนคำอธิบายภาพที่นี่

มีวิธีใดบ้างที่จะปิดฟีเจอร์หรือภาพหน้าจอนี้โดยสิ้นเชิง หรือฉันสามารถซ่อนแอปทั้งหมดจากตัวสลับได้หรือไม่ แอปจำเป็นต้องทำงานในพื้นหลัง แต่เราไม่ต้องการแสดงภาพหน้าจอใด ๆ จากแอป

ภาพหน้าจออาจมีความเสี่ยงด้านความปลอดภัยลองนึกถึงแอปธนาคารที่หมายเลขบัตรหรือข้อมูลสรุปบัญชีของคุณจะพร้อมใช้งานสำหรับทุกคนที่ดับเบิลคลิกที่ปุ่มโฮมบนอุปกรณ์

ใครมีข้อมูลเชิงลึกเกี่ยวกับเรื่องนี้ ขอบคุณ.


1
วิธีแก้ปัญหาปัจจุบันของฉันคือโหลดมุมมองเปล่าพร้อมโลโก้แอปเมื่อแอปเข้าสู่โหมดไฮเบอร์เนตและลบออกเมื่อแอปกลับมา แต่โซลูชันนั้นยากที่จะจัดการและดูเหมือนว่าจะเป็นการแฮ็กแทนที่จะเป็นโซลูชันที่สวยงาม นอกจากนี้โซลูชันนี้ยังล้มเหลวเป็นครั้งคราวขึ้นอยู่กับอุปกรณ์เป็นต้นดังนั้นจึงไม่สามารถใช้งานได้จริง
Tommie

คำตอบ:


101

ในการเตรียม UI ของคุณให้ทำงานในพื้นหลัง Apple กล่าวว่า:

เตรียม UI ของคุณสำหรับ App Snapshot

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

UI ของแอปของคุณต้องไม่มีข้อมูลผู้ใช้ที่ละเอียดอ่อนเช่นรหัสผ่านหรือหมายเลขบัตรเครดิต หากอินเทอร์เฟซของคุณมีข้อมูลดังกล่าวให้ลบออกจากมุมมองของคุณเมื่อเข้าสู่พื้นหลัง นอกจากนี้ปิดการแจ้งเตือนอินเทอร์เฟซชั่วคราวและตัวควบคุมมุมมองระบบที่บดบังเนื้อหาของแอปของคุณ สแนปชอตแสดงถึงอินเทอร์เฟซของแอปของคุณและผู้ใช้ควรจดจำได้ เมื่อแอปของคุณกลับสู่พื้นหน้าคุณสามารถกู้คืนข้อมูลและมุมมองได้ตามความเหมาะสม

ดูคำถามและคำตอบทางเทคนิค QA1838: การป้องกันไม่ให้ข้อมูลที่ละเอียดอ่อนปรากฏในตัวสลับงาน

นอกเหนือจากการปิดบัง / แทนที่ข้อมูลที่ละเอียดอ่อนแล้วคุณอาจต้องการบอกให้ iOS 7 ไม่ใช้สแนปชอตหน้าจอผ่านignoreSnapshotOnNextApplicationLaunchซึ่งมีเอกสารระบุว่า:

หากคุณรู้สึกว่าสแนปชอตไม่สามารถแสดงอินเทอร์เฟซผู้ใช้ของแอปของคุณได้อย่างถูกต้องเมื่อเปิดแอปอีกครั้งคุณสามารถโทรignoreSnapshotOnNextApplicationLaunchเพื่อป้องกันไม่ให้ถ่ายภาพสแนปชอตนั้นได้

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

หากนี่เป็นแอปสำหรับองค์กรคุณอาจต้องการดูการตั้งค่าที่เหมาะสมตามที่allowScreenShotระบุไว้ในส่วนข้อ จำกัด Payloadของการอ้างอิงโปรไฟล์การกำหนดค่า


นี่คือการนำไปใช้งานที่บรรลุสิ่งที่ฉันต้องการ คุณสามารถนำเสนอของคุณเองUIImageViewหรือคุณสามารถใช้รูปแบบโปรโตคอลตัวแทนเพื่อปิดบังข้อมูลที่เป็นความลับ:

//  SecureDelegate.h

#import <Foundation/Foundation.h>

@protocol SecureDelegate <NSObject>

- (void)hide:(id)object;
- (void)show:(id)object;

@end

จากนั้นฉันก็ให้แอปของฉันมอบหมายคุณสมบัติสำหรับสิ่งนั้น:

@property (weak, nonatomic) id<SecureDelegate> secureDelegate;

ตัวควบคุมมุมมองของฉันตั้งค่าไว้:

- (void)viewDidLoad
{
    [super viewDidLoad];

    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    delegate.secureDelegate = self;
}

เห็นได้ชัดว่าตัวควบคุมมุมมองใช้โปรโตคอลนั้น:

- (void)hide:(id)object
{
    self.passwordLabel.alpha = 0.0;
}

- (void)show:(id)object
{
    self.passwordLabel.alpha = 1.0;
}

และในที่สุดผู้แทนแอปของฉันก็ใช้ประโยชน์จากโปรโตคอลและคุณสมบัตินี้:

- (void)applicationWillResignActive:(UIApplication *)application
{
    [application ignoreSnapshotOnNextApplicationLaunch];  // this doesn't appear to work, whether called here or `didFinishLaunchingWithOptions`, but seems prudent to include it

    [self.secureDelegate hide:@"applicationWillResignActive:"];  // you don't need to pass the "object", but it was useful during my testing...
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [self.secureDelegate show:@"applicationDidBecomeActive:"];
}

หมายเหตุฉันใช้applicationWillResignActiveมากกว่าคำแนะนำapplicationDidEnterBackgroundเพราะอย่างที่คนอื่น ๆ ชี้ให้เห็นว่าหลังไม่ถูกเรียกเมื่อแตะสองครั้งที่ปุ่มโฮมในขณะที่แอปกำลังทำงาน

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


6
โปรดทราบว่าตามที่กล่าวไว้ในที่นี้stackoverflow.com/questions/18937313/…พฤติกรรมไม่เหมือนกันเสมอไปในโปรแกรมจำลองบนอุปกรณ์!
Michael Forrest

5
สำหรับสิ่งที่คุ้มค่าที่ignoreSnapshotOnNextApplicationLaunchวิธีการที่จะถูกละเว้นถ้ามันไม่ได้ถูกเรียกในช่วงการฟื้นฟูของรัฐตามที่อธิบายไว้ที่นี่
Charles A.

3
คุณไม่จำเป็นต้องทำใน applicationWillResignActive เนื่องจากไม่ได้ถ่ายภาพหน้าจอจนกว่า applicationDidEnterBackground เมื่อคุณแตะสองครั้งที่ปุ่มโฮมจะไม่มีการถ่ายภาพหน้าจอ หน้าจอที่คุณเห็นนั้นถ่ายทอดสด เพิ่มภาพเคลื่อนไหวลงในหน้าจอของคุณเพื่อตรวจสอบเช่นวนสีพื้นหลัง หากคุณเลือกแอปอื่น applicationDidEnterBackground ของคุณจะถูกเรียกก่อนที่จะถ่ายภาพหน้าจอจริง
honus

3
BTW ฉันได้รับแจ้งจากวิศวกรของ Apple ว่าเอกสารประกอบignoreSnapshotOnNextApplicationLaunchไม่ถูกต้องซึ่งตามที่เราทุกคนสังเกตเห็นว่ามีการถ่ายภาพรวม แต่จะไม่ถูกนำมาใช้ในการเปิดตัวครั้งต่อไป
Rob

2
ignoreSnapshotOnNextApplicationLaunch ดูเหมือนว่าจะทำสิ่งที่ดูเหมือน: ป้องกันหน้าจอจากการถูกแสดงระหว่างการเปิดตัว ไม่มีผลต่อภาพหน้าจอ UI แบบมัลติทาสก์หรือหากแอปพลิเคชันของคุณกลับมาทำงานต่อแทนที่จะเปิดตัว
Glenn Maynard

32

นี่คือโซลูชันที่ฉันใช้กับแอปพลิเคชันของฉัน:

ดังที่ทอมมี่กล่าวไว้: คุณสามารถใช้ applicationWillResignActive สิ่งที่ฉันทำคือการสร้าง UIImageView ด้วย SplashImage ของฉันและเพิ่มเป็นมุมมองย่อยในหน้าต่างหลักของฉัน -

(void)applicationWillResignActive:(UIApplication *)application
{
    imageView = [[UIImageView alloc]initWithFrame:[self.window frame]];
    [imageView setImage:[UIImage imageNamed:@"Portrait(768x1024).png"]];
    [self.window addSubview:imageView];
}

ฉันใช้วิธีนี้แทน applicationDidEnterBackground เนื่องจาก applicationDidEnterBackground จะไม่ถูกทริกเกอร์หากคุณแตะปุ่มโฮมสองครั้งและ applicationWillResignActive จะเป็น ฉันได้ยินคนพูดว่ามันสามารถถูกกระตุ้นได้ในกรณีอื่น ๆ เช่นกันดังนั้นฉันยังคงทดสอบเพื่อดูว่ามันก่อให้เกิดปัญหาหรือไม่ แต่ยังไม่มีเลย! ;)

ที่นี่เพื่อลบมุมมองภาพ:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(imageView != nil) {
        [imageView removeFromSuperview];
        imageView = nil;
    }
}

หวังว่านี่จะช่วยได้!

Sidenote: ฉันทดสอบสิ่งนี้ทั้งบนเครื่องจำลองและอุปกรณ์จริง: มันจะไม่แสดงบนเครื่องจำลอง แต่มันทำบนอุปกรณ์จริง!


2
มีข้อเสียเปรียบประการหนึ่ง: applicationWillResignActive ถูกเรียกในกรณีอื่น ๆ เมื่อผู้ใช้ดึงแท่นวางการแจ้งเตือนลง คุณจึงเลื่อนนิ้วจากบนลงล่างและดูรูปภาพนั้นในขณะที่คุณคาดว่าจะเห็นเนื้อหาของแอพ
Kirill Gamazkov

4
ควรเบลอข้อมูลที่ละเอียดอ่อนใน applicationWillResignActive และตั้งค่า imageView บน aplicationDidEnterBackground
Kirill Gamazkov

ใช้งานได้ แต่มีข้อผิดพลาดในการหมุนเมื่อนำไปใช้กับ iOS7 ซึ่งสร้างขึ้นด้วย xCode6: stackoverflow.com/questions/26147068/…
Alex Stone

หากฉันเขียนโค้ดที่คุณพูดถึงในapplicationWillResignActiveฉันจะเห็นอะไรเมื่อนำแอปของฉันกลับสู่สถานะเบื้องหน้า ฉันจะเห็นภาพ "Portrait (768x1024) .png" หรือหน้าจอจริงหรือไม่
NSPratik

2
@Pratik: คุณจะเห็นภาพเว้นแต่คุณจะลบออกอีกครั้งในวิธีการ applicationDidBecomeActive (ดูด้านบน)
Laura

14

วิธีที่ง่ายและรวดเร็วนี้จะให้สแนปชอตสีดำเหนือไอคอนแอพของคุณในตัวสลับแอพ iOS7 ขึ้นไป

ขั้นแรกให้ใช้หน้าต่างหลักของแอปของคุณ (โดยทั่วไปจะตั้งค่าใน AppDelegate.m ในแอปพลิเคชัน: didFinishLaunchingWithOptions) และซ่อนไว้เมื่อแอปของคุณกำลังจะย้ายไปอยู่เบื้องหลัง:

- (void)applicationWillResignActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        self.window.hidden = YES;
    }
}

จากนั้นยกเลิกการซ่อนหน้าต่างหลักของแอปเมื่อแอปของคุณกลับมาใช้งานได้อีกครั้ง:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        self.window.hidden = NO;
    }
}

ณ จุดนี้ให้ตรวจสอบตัวสลับแอปและตรวจสอบว่าคุณเห็นภาพรวมสีดำเหนือไอคอนของแอป ฉันสังเกตเห็นว่าหากคุณเปิดตัวสลับแอปทันทีหลังจากที่ย้ายแอปไปอยู่เบื้องหลังอาจมีความล่าช้าประมาณ 5 วินาทีซึ่งคุณจะเห็นภาพรวมของแอปของคุณ (อันที่คุณต้องการซ่อน!) ซึ่งจะเปลี่ยนเป็นสแนปชอตสีดำทั้งหมด ฉันไม่แน่ใจว่าเกิดอะไรขึ้นกับความล่าช้า หากใครมีข้อเสนอแนะกรุณากดเข้ามา

หากคุณต้องการสีอื่นที่ไม่ใช่สีดำในตัวสลับคุณสามารถทำสิ่งนี้ได้โดยการเพิ่มมุมมองย่อยด้วยสีพื้นหลังที่คุณต้องการ:

- (void)applicationWillResignActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        UIView *colorView = [[[UIView alloc] initWithFrame:self.window.frame] autorelease];
        colorView.tag = 9999;
        colorView.backgroundColor = [UIColor purpleColor];
        [self.window addSubview:colorView];
        [self.window bringSubviewToFront:colorView];
    }
}

จากนั้นลบมุมมองย่อยสีนี้เมื่อแอปของคุณกลับมาใช้งานอีกครั้ง:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if(isIOS7Or8)
    {
        UIView *colorView = [self.window viewWithTag:9999];
        [colorView removeFromSuperview];
    }
}

4

ฉันใช้วิธีแก้ปัญหาต่อไปนี้: เมื่อแอปพลิเคชันกำลังจะลาออกฉันจะได้รับ appWindow snapshot เป็น View และเพิ่มภาพเบลอลงไป จากนั้นฉันเพิ่มมุมมองนี้ในหน้าต่างแอพ

วิธีทำ:

  1. ใน appDelegate ก่อนการใช้งาน add line:

    static const int kNVSBlurViewTag = 198490;//or wherever number you like
    
  2. เพิ่มวิธีการนี้:

    - (void)nvs_blurPresentedView
        {
            if ([self.window viewWithTag:kNVSBlurViewTag]){
                return;
            }
            [self.window addSubview:[self p_blurView]];
        }
    
        - (void)nvs_unblurPresentedView
        {
            [[self.window viewWithTag:kNVSBlurViewTag] removeFromSuperview];
        }
    
        #pragma mark - Private
    
        - (UIView *)p_blurView
        {
            UIView *snapshot = [self.window snapshotViewAfterScreenUpdates:NO];
    
            UIView *blurView = nil;
            if ([UIVisualEffectView class]){
                UIVisualEffectView *aView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
                blurView        = aView;
                blurView.frame  = snapshot.bounds;
                [snapshot addSubview:aView];
            }
            else {
                UIToolbar *toolBar  = [[UIToolbar alloc] initWithFrame:snapshot.bounds];
                toolBar.barStyle    = UIBarStyleBlackTranslucent;
                [snapshot addSubview:toolBar];
            }
            snapshot.tag = kNVSBlurViewTag;
            return snapshot;
        }
    
  3. ทำให้การใช้งาน appDelegate ของคุณเป็นดังนี้:

    - (void)applicationWillResignActive:(UIApplication *)application {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        //...
        //your code
        //...
    
        [self nvs_blurPresentedView];
    }
    
        - (void)applicationWillEnterForeground:(UIApplication *)application {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        //...
        //your code
        //...
    
        [self nvs_unblurPresentedView];
    }
    

ฉันสร้างโครงการตัวอย่างในสวิฟท์และวัตถุประสงค์ C ทั้งสองโครงการดำเนินการต่อไปนี้ใน:

-application: didResignActive - สร้างภาพรวมเบลอและเพิ่มลงในหน้าต่างแอป

- แอปพลิเคชัน: willBecomeActiveเบลอมุมมองจะถูกลบออกจากหน้าต่าง

วิธีใช้:

Objecitve C.

  1. เพิ่มAppDelegate+NVSBlurAppScreenไฟล์. h และ. m ในโปรเจ็กต์ของคุณ

  2. ใน -applicationWillResignActive ของคุณ: วิธีการเพิ่มบรรทัดต่อไปนี้:

    [self nvs_blurPresentedView];
    
  3. ใน -applicationDidEnterBackground ของคุณ: วิธีการเพิ่มบรรทัดต่อไปนี้:

    [self nvs_unblurPresentedView];
    

รวดเร็ว

  1. เพิ่มไฟล์ AppDelegateExtention.swift ในโปรเจ็กต์ของคุณ

  2. ในแอปพลิเคชันของคุณฟังก์ชัน WillResignActive ให้เพิ่มบรรทัดต่อไปนี้:

    blurPresentedView()
    
  3. ในฟังก์ชัน ApplicationDidBecomeActive ของคุณให้เพิ่มบรรทัดต่อไปนี้:

    unblurPresentedView()
    

2

หากใช้เฉพาะ[self.window addSubview:imageView];ในapplicationWillResignActiveฟังก์ชัน imageView นี้จะไม่ครอบคลุม UIAlertView, UIActionSheet หรือ MFMailComposeViewController ...

ทางออกที่ดีที่สุดคือ

- (void)applicationWillResignActive:(UIApplication *)application
{
    UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
    [mainWindow addSubview:imageView];
}

ทางออกที่ดีมากหากคุณมีวิดีโอที่เล่นในโหมดเต็มหน้าจอใน webview!
Tommie

ยอดเยี่ยม!. มันใช้งานได้แม้ว่าเราจะเปิดปุ่มกดก่อนที่จะเข้าสู่ตัวสลับมัลติทาสก์ก็ตาม! ขอบคุณ
Prabhu.Somasundaram

0

ให้คำตอบของตัวเองเป็น "คำตอบ" แม้ว่าโซลูชันนี้จะไม่น่าเชื่อถือมากก็ตาม บางครั้งฉันได้หน้าจอสีดำเป็นภาพหน้าจอบางครั้ง XIB และบางครั้งก็เป็นภาพหน้าจอจากแอป ขึ้นอยู่กับอุปกรณ์และ / หรือหากฉันเรียกใช้สิ่งนี้ในโปรแกรมจำลอง

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

ใน AppDelegate.m ภายใต้ applicationWillResignActive ฉันตรวจสอบว่าเรากำลังใช้งาน iOS7 หรือไม่หากเราโหลดมุมมองใหม่ซึ่งว่างเปล่าโดยมีโลโก้แอปอยู่ตรงกลาง เมื่อ applicationDidBecomeActive ถูกเรียกว่าฉันเปิดมุมมองเก่าของฉันอีกครั้งซึ่งจะถูกรีเซ็ต - แต่ใช้ได้กับประเภทของแอปพลิเคชันที่ฉันกำลังพัฒนา


1
หากคุณเห็นสิ่งที่แอป Camera ทำ - จะเปลี่ยนภาพเป็นภาพเบลอเมื่อเข้าสู่พื้นหลัง (คุณสามารถเห็นการเปลี่ยนแปลงเมื่อลดเป็นไอคอน)
Petesh

@Petesh ใช่นั่นเป็นการใช้งานที่ดี แต่คำถามคือพวกเขาทำได้อย่างไร ฉันกลัว API ส่วนตัว
Rob

@Tommie คุณพูดว่า "ขึ้นอยู่กับอุปกรณ์และ / หรือถ้าฉันเรียกใช้สิ่งนี้ในโปรแกรมจำลอง" สำหรับฉันดูเหมือนว่าจะใช้งานได้กับอุปกรณ์ (แม้ว่าฉันยังไม่ได้ทำการทดสอบอย่างละเอียดถี่ถ้วน) แต่ไม่ใช่ตัวจำลอง คุณพบว่ามันไม่ทำงานบนอุปกรณ์หรือไม่?
Rob

0

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


-2

Xamarin.iOS

ดัดแปลงมาจากhttps://stackoverflow.com/a/20040270/7561

แทนที่จะแสดงสี แต่ฉันต้องการแสดงหน้าจอเริ่มต้นของฉัน

 public override void DidEnterBackground(UIApplication application)
 {
    //to add the background image in place of 'active' image
    var backgroundImage = new UIImageView();
    backgroundImage.Tag = 1234;
    backgroundImage.Image = UIImage.FromBundle("Background");
    backgroundImage.Frame = this.window.Frame;
    this.window.AddSubview(backgroundImage);
    this.window.BringSubviewToFront(backgroundImage);
}

public override void WillEnterForeground(UIApplication application)
{
    //remove 'background' image
    var backgroundView = this.window.ViewWithTag(1234);
    if(null != backgroundView)
        backgroundView.RemoveFromSuperview();
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.