My Wish for Google I/O 2015: A New Gmail API

I am looking forward to seeing what Google will announce at its I/O conference next week. My biggest wish is for a new Gmail API.

Last year, Google announced its first Gmail API. POP, IMAP, and even some Gmail-specific IMAP extensions had been available, but this was the first HTTP-based API for Gmail. It is a start, but it has some weaknesses.

The data returned when retrieving a list of objects from the Gmail API is minimal. If you request a list of messages, the response will contain only the Message ID and Thread ID of each message. If you want the subject of each message, you need to issue a separate “get” request for each message.

You can batch these “get” requests. The mechanism for batching requests is to send multiple requests in a batch request. A batch request is made up of multiple requests combined into a “multipart/mixed” HTTP request body. Each request in the batch includes its own set of HTTP headers. The response is a “multipart/mixed” response containing a full HTTP response for each batched request. The end result is that retrieving the message subjects for the newest 100 messages in your inbox requires two HTTP requests. The second request and second response will be bloated with the HTTP headers and MIME part separators for each request and response in the batch.

The Gmail API also has no mechanism for retrieving or modifying Gmail filters. Neither the Gmail iOS app nor the Gmail mobile web app allow the user to view or set filters. I can appreciate why Google would keep the mobile interfaces simple, but I wish Google would let a third party developer build an iOS app to manage Gmail filters.

Late last year, FastMail announced JMAP. JMAP is a proposed standard protocol for synchronizing a mail client with a mail server. JMAP supports the concept of messages being associated with more than one mailbox, just as Gmail messages can be associated with more than one label. Its approach to batching requests and responses requires less overhead. JMAP support is not yet available from any email provider – not even FastMail, but I hope to see that change. Like the Gmail API, JMAP does nothing for filters.

I would like to see Google either adopt JMAP or use some of the ideas behind JMAP to improve the Gmail API. I would also like to see an API that supported retrieving and updating filters.

TestFlight Observation

I just submitted the first Marcato 1.1 beta to TestFlight. I was not asked if there were “significant changes”. The build is now pending review for release to beta testers. Since this is the first beta build after a release build, I am guessing that Apple assumes that there are significant changes.

I tried to remove the build from review and resubmit it to ensure that I did not just miss the question, but the “Remove From Review” link did nothing when I clicked on it.

Marcato

I just released a new app, Marcato. Marcato allows you to create site-specific browsers for your iPhone. Please check it out.

Recording Videos for iOS Apps

I recently spent a great deal of time creating app videos for Marcato. I prepared one video for my web site, and one App Preview for each of three screen sizes (4-inch, 4.7-inch, and 5.5-inch) for the App Store.

Apple made some improvements in iOS 8 and Yosemite to make recording videos easier, but some aspects of the process are still tricky. I wanted to describe how I went about this here.

Automating the Actions

Videos will need to be recorded many times. The App Store requires a separate video for each screen size. The app will evolve over time, requiring updates to the videos. The desired content of the videos will change over time.

I did not want to simply record myself navigating through the app. I would need to manually do that navigation every time, and would undoubtedly make numerous typos and unintentional taps. Instead, I created a custom build of the app using a separate build target that followed my script. The script is as simple as:

  1. 3 seconds after the app is launched, show a button as highlighted.
  2. .1 seconds after that, unhighlight the button and tell its target to perform its action.
  3. 2 seconds after that, do something else.

I use Kent Sutherland's great KSScreenshotManager library to help automate the process. Its goal is to automatically generate screenshots, but part of that involves setting up a sequence of automated actions. I needed to remove KSScreenshotManager's calls to UIGetScreenImage(), as that function was removed from the 64-bit iOS SDK. I did not need to take screenshots for this task anyhow.

I created a separate Xcode build target that creates a custom build of the app. The custom build of the app starts with an empty data set and follows my script.

Customizing the Status Bar

Ideally, I want the status bar to look like this:

When using QuickTime Player to record from the device, QuickTime Player will make the status bar look like that regardless of how the status bar on the device would otherwise look. When recording from the simulator, the status bar will look more like this:

The word “Carrier” would stick out like a sore thumb. I used XCDFakeCarrier to make the custom build of the app show five bullets instead of “Carrier”, and 9:41 AM instead of the time of recording.

Text overlays

Text overlays can be added in iMovie, but I find it better to add them directly into the custom build of the app used to record the video. That way, I add the overlays once and they are in every version of the video that I record. I don't need to redo that work unless I change the overlays themselves.

I did this by creating a second UIWindow just for overlays, and then creating a view controller to show the overlays:

+ (GHSTextOverlayViewController*) sharedInstance { static GHSTextOverlayViewController* inst = nil; static GHSOverlayWindow* overlayWindow = nil; if (!inst) { overlayWindow = [[GHSOverlayWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; [overlayWindow makeKeyAndVisible]; inst = [[GHSTextOverlayViewController alloc] init]; [overlayWindow setRootViewController:inst]; } return inst; }

GHSOverlayWindow is a simple subclass of UIWindow that overrides hitTest:withEvent:, returning false. This ensures that the window does not intercept touch events, and therefore that the app's primary UIWindow receives and processes those touch events.

@implementation GHSOverlayWindow - (UIView *) hitTest:(CGPoint)point withEvent:(UIEvent *)event { return nil; } @end

GHSOverlayViewController manages the overlay view. The overlay view is transparent, except for the text and framing it adds to the screen. It can be made to fade text in or out of view.

Recording

Apple recommends that App Previews be recorded from the device rather than the simulator. QuickTime Player has explicit support for recording iOS device screens, but not simulator screens. Since I do not have an iPhone 6 or iPhone 6 Plus, I needed to record for the 4.7” screen size and 5.5” screen size from the simulator.

I followed these steps to record from the simulator:

  1. On the Mac, open the “Desktop & Screen Saver” System Preferences panel and choose a solid color for the desktop pattern. Choose a color that is very different from the colors in the app. This will help to precisely identify and select the portion of the screen that represents the simulated iPhone screen.
  2. My best display is the 15-inch retina display built into my MacBook Pro. In its default configuration, the iPhone 6 Plus simulator cannot run on that screen without scrolling. To make recording the screen feasible, I set the screen resolution to that providing the most screen real estate using the “Displays” System Preferences panel. The availability of adequate resolutions may depend on the display.
  3. Use Xcode to launch the custom build of the app in the appropriate device simulator. Don't worry about recording it yet; just let it run. Move windows around in a manner such that the simulator window occupies its own portion of the screen, with no other windows behind it or near it.
  4. Open QuickTime Player and select “New Screen Recording” under the File menu.
  5. In the resulting window, click the red record button. A text overlay will appear that reads, “Click to record the full screen. Drag to record part of the screen. End recording by clicking the stop button in the menu bar.” Drag a rectangle around the portion of the simulator window that represents the device screen. After generating the original rectangle, drag its edges to more precisely select the area of the device screen. When done, click on the “Start Recording” button at the center of the area.
  6. Use Xcode to stop and restart the custom build of the app in the simulator again.
  7. Once the custom build has finished its sequence of steps, stop the recording using the stop button in the menu bar.
  8. Save the recorded video. Choose a filename that indicates the device size and that it is raw, unedited, video so that it can be distinguished from the other movie files.

Resizing the iPhone 6 Plus Video

This is probably unnecessary when recording from the device, but iPhone 6 Plus raw video recorded using the simulator will need to be resized. The simulator recording will be 1242 x 2208. iTunes Connect requires a 1080 x 1920 recording. The video can be downsampled using MPEG Streamclip as follows:

  1. Download and install MPEG Streamclip.
  2. Launch MPEG Streamclip.
  3. Select “Open Files…” from the File menu, and select the raw video for the iPhone 6 Plus.
  4. Select “Export to QuickTime…” from the File Menu. In the resulting dialog box, select the “Other” button under “Frame Size” and enter a frame size of 1080 x 1920. Select “H.264” as the type of Compression. Click the “Make Movie” button.

The video exported from MPEG Streamclip is the one to import into iMovie later.

Audio

I chose to use a musical background and not to add any voiceovers. I licensed music inexpensively from AudioJungle.

Editing

I am not going to cover editing in any detail here. I used iMovie. The most important things to remember are:

  • When creating the video, select “New App Preview” under the File menu.
  • When exporting the video, select “App Preview…” under the Share submenu of the File menu.

If those two steps are followed, iMovie will ensure that the resulting movies have the dimensions and other characteristics required by iTunes Connect.

App Approval Glitch

Initially I used the New York Times and Twitter as sample web sites for the video and screenshots. Apple rejected the submission based on New York Times pages appearing in screenshots, citing this rule:

8.5 - Apps may not use protected third party material such as trademarks, copyrights, patents or violate 3rd party terms of use. Authorization to use such material must be provided upon request

I thought this would be considered fair use, but the best information I found indicates that this would infringe. I resorted to using my own blog and a simulated internal site for my own company.

I would much prefer to include web sites of more general interest, but doing so and staying clear of intellectual property issues and App Store approval problems is not as easy as I had believed.

Final Notes

Apple requires that App Previews be no more than 30 seconds long. I created a longer video for my web site.

iTunes Connect does not allow App Previews for 3.5-inch devices such as the iPhone 4S.

There is undoubtedly room to improve this process and to automate more of it.

Other Resources

Joe Cieplinski: Build Your Own Product and Videos and Live Previews
Joe Cieplinski's talk on the subject from 360iDev

The Making and Effectiveness of an App Preview
David Smith's blog post and video on building App Previews

Creating Great App Previews
A WWDC talk regarding App Previews


Update April 10, 2015:Brian King points out ASScreenRecorder, a library making it easier to record videos from within your app.

My mailbox

My mailbox has its own igloo.