Mengontrol tangkapan layar di pengalih multitasking iOS 7

98

Saya telah mencoba menemukan beberapa informasi mengenai pengalih multitasking baru di iOS 7 dan terutama tangkapan layar yang diambil OS saat aplikasi masuk ke mode hibernasi.

masukkan deskripsi gambar di sini

Apakah ada cara untuk mematikan fitur atau tangkapan layar ini sepenuhnya? Atau dapatkah saya menyembunyikan aplikasi sekaligus dari pengalih? Aplikasi perlu berjalan di latar belakang, tetapi kami tidak ingin menampilkan tangkapan layar apa pun dari aplikasi.

Tangkapan layar berpotensi berisiko keamanan, pikirkan di sepanjang garis untuk aplikasi perbankan di mana nomor kartu atau ringkasan akun Anda akan tersedia untuk siapa saja yang mengklik dua kali tombol beranda pada perangkat.

Adakah yang tahu tentang ini? Terima kasih.

Tommie
sumber
1
Solusi saya saat ini adalah memuat tampilan kosong dengan logo aplikasi setelah aplikasi memasuki hibernasi dan menghapusnya saat aplikasi kembali, tetapi solusi itu sulit dikelola dan tampak seperti peretasan daripada solusi elegan. Selain itu, solusi ini gagal dari waktu ke waktu tergantung pada perangkat, dll. Jadi, ini tidak benar-benar dapat digunakan.
Tommie

Jawaban:

101

Dalam Mempersiapkan UI Anda untuk Berjalan di Latar Belakang , Apple mengatakan:

Siapkan UI Anda untuk App Snapshot

Di beberapa titik setelah aplikasi Anda memasuki latar belakang dan metode delegasi Anda kembali, UIKit mengambil snapshot dari antarmuka pengguna aplikasi Anda saat ini. Sistem menampilkan gambar yang dihasilkan di pengalih aplikasi. Ini juga menampilkan gambar untuk sementara saat membawa aplikasi Anda kembali ke latar depan.

UI aplikasi Anda tidak boleh berisi informasi pengguna yang sensitif, seperti sandi atau nomor kartu kredit. Jika antarmuka Anda berisi informasi seperti itu, hapus dari tampilan Anda saat memasuki latar belakang. Selain itu, tutup peringatan, antarmuka sementara, dan pengontrol tampilan sistem yang mengaburkan konten aplikasi Anda. Snapshot tersebut mewakili antarmuka aplikasi Anda dan harus dapat dikenali oleh pengguna. Saat aplikasi Anda kembali ke latar depan, Anda bisa memulihkan data dan tampilan sebagaimana mestinya.

Lihat T&J Teknis QA1838: Mencegah Informasi Sensitif Muncul di Pengalih Tugas

Selain mengaburkan / mengganti informasi sensitif, Anda mungkin juga ingin memberi tahu iOS 7 untuk tidak mengambil cuplikan layar melalui ignoreSnapshotOnNextApplicationLaunch, yang dokumentasinya mengatakan:

Jika Anda merasa bahwa snapshot tidak dapat dengan benar mencerminkan antarmuka pengguna aplikasi Anda saat aplikasi Anda diluncurkan kembali, Anda dapat memanggil ignoreSnapshotOnNextApplicationLaunchuntuk mencegah pengambilan gambar snapshot tersebut.

Karena itu, tampaknya snapshot layar masih diambil dan oleh karena itu saya telah mengajukan laporan bug. Tetapi Anda harus menguji lebih lanjut dan melihat apakah menggunakan pengaturan ini membantu.

Jika ini adalah aplikasi perusahaan, Anda mungkin juga ingin melihat pengaturan yang sesuai yang allowScreenShotdiuraikan di bagian Batasan Muatan dari Referensi Profil Konfigurasi.


Berikut adalah implementasi yang mencapai apa yang saya butuhkan. Anda dapat mempresentasikan milik Anda sendiri UIImageView, atau Anda dapat menggunakan pola protokol-delegasi untuk mengaburkan informasi rahasia:

//  SecureDelegate.h

#import <Foundation/Foundation.h>

@protocol SecureDelegate <NSObject>

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

@end

Saya kemudian memberikan properti kepada delegasi aplikasi saya untuk itu:

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

Pengontrol tampilan saya menyetelnya:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

Pengontrol tampilan jelas mengimplementasikan protokol itu:

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

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

Dan, akhirnya, delegasi aplikasi saya memanfaatkan protokol dan properti ini:

- (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:"];
}

Catatan, saya menggunakan applicationWillResignActivedaripada yang disarankan applicationDidEnterBackground, karena, seperti yang ditunjukkan orang lain, yang terakhir tidak dipanggil saat mengetuk dua kali tombol beranda saat aplikasi sedang berjalan.

Saya berharap saya dapat menggunakan pemberitahuan untuk menangani semua ini, daripada pola protokol-delegasi, tetapi dalam pengujian terbatas saya, pemberitahuan tidak ditangani secara tepat waktu, tetapi pola di atas berfungsi dengan baik.

rampok
sumber
6
Perhatikan bahwa, seperti yang disebutkan di sini stackoverflow.com/questions/18937313/… perilakunya tidak selalu sama di simulator seperti di perangkat!
Michael Forrest
5
Untuk apa nilainya, ignoreSnapshotOnNextApplicationLaunchmetode ini diabaikan jika tidak dipanggil selama pemulihan status, seperti yang dijelaskan di sini .
Charles A.
3
Anda tidak perlu melakukannya di applicationWillResignActive karena tangkapan layar tidak diambil hingga applicationDidEnterBackground. Saat Anda mengetuk dua kali tombol beranda, tidak ada tangkapan layar yang diambil; layar yang Anda lihat sedang live. Tambahkan animasi ke layar Anda untuk memverifikasi, misalnya warna latar belakang siklus. Jika Anda kemudian memilih aplikasi lain, applicationDidEnterBackground Anda akan dipanggil sebelum tangkapan layar yang sebenarnya diambil.
honus
3
BTW, saya diberi tahu oleh seorang insinyur Apple bahwa dokumentasinya ignoreSnapshotOnNextApplicationLaunchtidak benar, bahwa, seperti yang kita semua amati, snapshot sebenarnya diambil, tetapi tidak akan digunakan pada peluncuran berikutnya.
Rob
2
ignoreSnapshotOnNextApplicationLaunch sepertinya melakukan apa yang terdengar: mencegah tangkapan layar ditampilkan selama peluncuran aplikasi . Itu tidak memengaruhi tangkapan layar UI multitasking, atau jika aplikasi Anda sedang dilanjutkan daripada diluncurkan.
Glenn Maynard
32

Ini adalah solusi yang saya kerjakan untuk aplikasi saya:

Seperti yang dikatakan Tommy: Anda dapat menggunakan applicationWillResignActive. Apa yang saya lakukan adalah membuat UIImageView dengan SplashImage saya dan menambahkannya sebagai subview ke jendela utama saya-

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

Saya menggunakan metode ini daripada applicationDidEnterBackground karena applicationDidEnterBackground tidak akan dipicu jika Anda mengetuk dua kali tombol beranda, dan applicationWillResignActive akan terpicu. Saya mendengar orang mengatakan meskipun itu dapat dipicu dalam kasus lain juga, jadi saya masih menguji sekitar untuk melihat apakah itu memberi masalah, tetapi sejauh ini tidak ada! ;)

Di sini untuk menghapus imageview:

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

Semoga ini membantu!

Catatan: Saya mengujinya pada simulator dan perangkat nyata: Ini Tidak Akan Ditampilkan di simulator, tetapi pada perangkat nyata!

Laura
sumber
2
Ada satu kelemahan: applicationWillResignActive dipanggil, di antara kasus lainnya, saat pengguna menurunkan dok notifikasi. Jadi Anda menggeser jari Anda dari atas ke bawah dan melihat gambar itu, sementara Anda mengharapkan untuk melihat konten aplikasi.
Kirill Gamazkov
4
Lebih baik mengaburkan informasi sensitif pada applicationWillResignActive dan mengatur imageView pada aplicationDidEnterBackground
Kirill Gamazkov
Ini berfungsi, tetapi ada bug rotasi saat diterapkan ke iOS7, dibangun dengan xCode6: stackoverflow.com/questions/26147068/…
Alex Stone
Jika saya menulis kode yang Anda sebutkan di applicationWillResignActive , lalu apa yang akan saya lihat saat mengembalikan Aplikasi ke status latar depan? Apakah saya akan melihat gambar "Potret (768x1024) .png" atau layar sebenarnya?
NSPratik
2
@Pratik: Anda akan melihat gambar, kecuali Anda menghapusnya lagi dalam metode applicationDidBecomeActive (lihat di atas).
Laura
14

Metode cepat dan mudah ini akan menghasilkan snapshot hitam di atas ikon aplikasi Anda di iOS7 atau pengalih aplikasi yang lebih baru.

Pertama, ambil jendela kunci aplikasi Anda (biasanya disiapkan di AppDelegate.m dalam application: didFinishLaunchingWithOptions), dan sembunyikan saat aplikasi Anda akan dipindahkan ke latar belakang:

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

Kemudian, hapus-sembunyikan jendela kunci aplikasi Anda saat aplikasi Anda kembali aktif:

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

Pada titik ini, periksa pengalih aplikasi dan verifikasi bahwa Anda melihat snapshot hitam di atas ikon aplikasi Anda. Saya perhatikan bahwa jika Anda meluncurkan pengalih aplikasi segera setelah memindahkan aplikasi Anda ke latar belakang, mungkin ada penundaan ~ 5 detik di mana Anda akan melihat cuplikan aplikasi Anda (yang ingin Anda sembunyikan!), Setelah yang dialihkan ke snapshot serba hitam. Saya tidak yakin ada apa dengan penundaan itu; jika ada yang punya saran, silakan bergabung.

Jika Anda menginginkan warna selain hitam di pengalih, Anda dapat melakukan sesuatu seperti ini dengan menambahkan subview dengan warna latar belakang yang Anda inginkan:

- (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];
    }
}

Lalu, hapus subview warna ini saat aplikasi Anda kembali aktif:

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

Saya menggunakan solusi berikut: ketika aplikasi akan mengundurkan diri saya mendapatkan snapshot appWindow sebagai Tampilan dan menambahkan blur padanya. Lalu saya menambahkan tampilan ini ke jendela aplikasi

bagaimana cara melakukannya:

  1. di appDelegate sebelum implementasi tambahkan baris:

    static const int kNVSBlurViewTag = 198490;//or wherever number you like
  2. tambahkan metode ini:

    - (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. buat implementasi appDelegate Anda menjadi seperti berikut:

    - (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];
    }
    

Saya membuat proyek Contoh di Swift dan Objective C . Kedua proyek melakukan tindakan berikut dalam:

-aplikasi: didResignActive - snapshot dibuat, diburamkan dan ditambahkan ke jendela aplikasi

-aplikasi: tampilan blur willBecomeActive sedang dihapus dari jendela.

Cara Penggunaan:

Objecitve C

  1. Tambahkan AppDelegate+NVSBlurAppScreenfile .h dan .m ke proyek Anda

  2. di metode -applicationWillResignActive Anda: tambahkan baris berikut:

    [self nvs_blurPresentedView];
  3. di metode -applicationDidEnterBackground Anda: tambahkan baris berikut:

    [self nvs_unblurPresentedView];

Cepat

  1. tambahkan file AppDelegateExtention.swift ke proyek Anda

  2. dalam fungsi applicationWillResignActive Anda, tambahkan baris berikut:

    blurPresentedView()
  3. dalam fungsi applicationDidBecomeActive Anda, tambahkan baris berikut:

    unblurPresentedView()
Nikolay Shubenkov
sumber
2

jika hanya digunakan [self.window addSubview:imageView];dalam applicationWillResignActivefungsi, imageView ini tidak akan mencakup UIAlertView, UIActionSheet atau MFMailComposeViewController ...

Solusi terbaik adalah

- (void)applicationWillResignActive:(UIApplication *)application
{
    UIWindow *mainWindow = [[[UIApplication sharedApplication] windows] lastObject];
    [mainWindow addSubview:imageView];
}
Zorot
sumber
Solusi yang sangat bagus jika Anda memutar video dalam mode layar penuh dalam tampilan web!
Tommie
Luar biasa !. Ini berfungsi bahkan jika kita memiliki keypad terbuka sebelum masuk ke pengalih multitasking! Terima kasih
Prabhu.Somasundaram
0

Memberikan solusi saya sendiri sebagai "jawaban", padahal solusi ini sangat tidak bisa diandalkan. Terkadang saya mendapatkan layar hitam sebagai tangkapan layar, terkadang XIB dan terkadang tangkapan layar dari aplikasi itu sendiri. Bergantung pada perangkat dan / atau jika saya menjalankan ini di simulator.

Harap diperhatikan bahwa saya tidak dapat memberikan kode apa pun untuk solusi ini karena ada banyak detail khusus aplikasi di sana. Tetapi ini harus menjelaskan inti dasar solusi saya.

Di AppDelegate.m di bawah applicationWillResignActive saya memeriksa apakah kita menjalankan iOS7, jika kita melakukannya, saya memuat tampilan baru yang kosong dengan logo aplikasi di tengah. Setelah applicationDidBecomeActive dipanggil, saya meluncurkan kembali tampilan lama saya, yang akan disetel ulang - tetapi berfungsi untuk jenis aplikasi yang saya kembangkan.

Tommie
sumber
1
Jika Anda melihat apa yang dilakukan aplikasi Kamera - itu mentransisikan gambar menjadi buram saat masuk ke latar belakang (Anda dapat melihat transisi saat itu berkurang ke ikon)
Petesh
@ Petesh Ya, itu implementasi yang bagus, tetapi pertanyaannya adalah bagaimana mereka melakukannya. Saya takut dengan API pribadi.
Rob
@Tommie Anda mengatakan "Tergantung pada perangkat dan / atau jika saya menjalankan ini di simulator". Bagi saya, ini tampaknya berfungsi pada perangkat (meskipun saya belum melakukan pengujian menyeluruh), tetapi tidak pada simulator. Apakah menurut Anda itu tidak berfungsi di perangkat?
Rob
0

Anda dapat menggunakan aktivator untuk mengonfigurasi klik ganda tombol beranda untuk meluncurkan multitasking dan menonaktifkan klik ganda default tombol beranda dan meluncurkan jendela multitasking. Metode ini dapat digunakan untuk mengubah tangkapan layar ke gambar default aplikasi. Ini berlaku untuk aplikasi dengan fitur perlindungan kode sandi default.

Fareed.MK
sumber
-2

Xamarin.iOS

Diadaptasi dari https://stackoverflow.com/a/20040270/7561

Alih-alih hanya menunjukkan warna, saya ingin menunjukkan layar peluncuran saya.

 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();
}
ben
sumber