Skip to main content

Sleeping Beauty - Making your iOS app sleeping beautifully

·5 mins

Sometimes you will find yourself creating an app which contains sensitive user information. I found myself there. Of course, you want to protect it the best you can. So you encrypt it, double salt it, encrypt it again, put it in a fortified building, set it up with Touch ID. Yet a small forgotten detail could leave you out in the cold.

A feature that is quickly overlooked, but can leak information nonetheless is the multitask screen on iOS. When you double press the home button, a handy overview screen comes up with which you can easily switch to another app. And while doing so it looks crazy sexy! But. To make it look so good, Apple takes a snapshot of your screen just before it gets send to the background, and that screen might just contain some information that you do not want to be seen.

This was a situation I found myself in for a recent project, and so I set out on a new adventure, making my app sleep like a beauty.

Although I am aware that Windows Phone and Android have similar functionality, the project was targeting only iOS, so my solution is limited to this OS only. (edit; see the end of the post for an edit which works for Android) If you have done this for one of the other platforms please share it so I can learn from you!

Good night! #

Actually there are a few ways to do it;

  • Hide the content of the current screen altogether;
  • Give it a nice blur of sorts; (thank you Daniel Cabrera!)
  • Show a static image.

And probably some more I didn’t think of. Basically you can create any kind of view as we will see later on.

While we found this to be important to our project, it (of course) could not take up to much of our time. For this we choose the easiest, yet good looking solution and would just show a static image. Which also happens to be the splashscreen! Talk about multitasking!

So how to go about it.

First, we have to tell iOS to stop taking screenshots of our app when we put it to sleep. For this we use the IgnoreSnapshotOnNextApplicationLaunch method.

Then there are two events that are of importance in your AppDelegate; the OnResignActivation and OnActivated. These simply do as one might expect: do stuff when the app is going to the background and when it is activated again. Actually in retrospect there might be more suited events because these also fire when you slide down the notification center or swipe up to use the command center which is a bit overkill. But hey, better safe than sorry!

Now that we have identified all of our ingredients let’s put them together. First lets dissect the part where we sent our app to the background.

// Obscure UI in multitasking view public override void OnResignActivation(UIApplication uiApplication) { base.OnResignActivation(uiApplication);

  // Prevent taking snapshot
  uiApplication.IgnoreSnapshotOnNextApplicationLaunch();

  // Create our hiding view which is transparent initially. Also note the tag I'm giving the view. Why 42 you ask..?
  var bgView = new UIImageView(UIImage.FromFile("Default-Landscape.png")) { Tag = 42, Alpha = 0 };

  // Add the view to our current window
  uiApplication.KeyWindow.AddSubview(bgView);
  uiApplication.KeyWindow.BringSubviewToFront(bgView);

  // Animate it to the front and thus hide the contents of the app
  UIView.Animate(0.5, () =>
  {
     bgView.Alpha = 1;
  });

}

If added comments to the code so it should be self-explanatory. The only part that probably needs some extra attention is why I am giving the view a tag. This is so we can later find the view by this tag to hide it again. Again, in retrospect there are probably more elegant ways to go about this. You probably want to declare a private variable in which you create the hiding view. I haven’t tried if that works, so please let me know if you have any improvements! O and 42 can of course be anything, as long as it is the same in our OnActivated event.

Also, as I said, we have recycled the splashscreen for this. The app was a iPad app which would only be used in landscape mode, so this was the easiest way. If you have a app which can rotate you probably have to apply some of your own magic to determine the correct width and height of your hiding view, which is probably easiest to just get by copying it off the uiApplication.KeyWindow.Frame. Also see the example GitHub.

Like I have stated earlier; you could build any view you like here, whatever looks best to you and best suits your needs. Just keep in mind that it has to perform!

In the OnActivated event we do roughly the reverse.

// Bring back main interface from obscuring public override void OnActivated(UIApplication uiApplication) { base.OnActivated(uiApplication);

    // Find our hiding view by the same tag we saw earlier
var view = uiApplication.KeyWindow.ViewWithTag(42);

    // If we found it, hide it again!
if (view != null)
{
       // Animate it back to transparent
   UIView.Animate(0.5, () =>
   {
      view.Alpha = 0;
   }, () =>
   {
            // And after that completed, remove te view altogether
	view.RemoveFromSuperview();
       });
}

}

In this code I have added some comments as well so the working should be pretty obvious.

While running it looks like this.

Sleeping Beauty in action

All code can be found in a GitHub repository. It may slightly differ from the code and what I have described above because it is code from an actual app, which exposes potential private data so it would be a bit awkward if I would just post screenshots of it here ;)

If you have any questions or remarks please let me know!

Now with extra Android! #

While browsing the Xamarin Forums I’ve accidentally found a way to do this for Android as well. It is much simpeler even!

Just add the line of code below in the OnCreate of your main Activity and let the OS do it for you!

Window.SetFlags(WindowManagerFlags.Secure, WindowManagerFlags.Secure);