Archive for January 20, 2015

Tuesday, January 20, 2015

WKWebView, Sandboxing, and Searching

Brent Simmons:

But the new replacement for WebView — WKWebView — doesn’t have this bug. Which is great. Let’s adopt the new thing! I’m all in. Love new things.


I did some research, and I learned that WKWebView won’t show local content — that is, files that are loaded from the app’s bundle. Files from the app bundle ought to be a-okay, ought not be a sandbox violation, but apparently they are.


In an ideal world, WKWebView would work with files from the app bundle, and, as a replacement for WebView, it would have the same functionality as WebView (a searchFor or equivalent method). Anything else means running as fast as I can while I slip backwards.

Update (2015-01-21): Chromium (via Martin Schurrer):

Unfortunately, despite the advantages of WKWebView, it has some significant technical limitations that UIWebView does not, which means we can’t simply drop it in as a replacement.

Update (2015-01-24): Dan Fabulich:

There is a workaround, demonstrated by shazron here to copy files into /tmp and load them from there.

Update (2015-04-23): The bug is still present in iOS 8.4b1.

Backing Up Discontinued Apps

Electronic Arts (via John Gordon):

EA is removing several of its older titles from the App Store, but if you already own these games, you will still be able to play them without interruption.

As always, we encourage our players to back up their app purchases in iCloud. If you uninstall the app without backing it up on iCloud or iTunes, you may not be able to redownload your game.

My understanding is that iCloud only backs up App Data. So if you want to restore an app that has been removed from the store you would need to have a backup in iTunes. And that app will probably never work with Family Sharing.

The Shape of the App Store

Charles Perry (tweet):

I expected a “hockey stick” curve that’s characteristic of power law models, but I didn’t expect one like this. The hockey stick breaks upwards at around position 870 on the U.S. Top Grossing list. With about 1.2 million apps in the App Store at the time the data was collected, that arguably puts 99.93% of apps in the “long tail” of the App Store. The “head” of the App Store, those 870 top grossing apps that make up 0.07% of the App Store population, collect over 40% of the App Store revenue that’s paid out.

Luckily, there’s a lot of money to be made in that long tail. At the top of the long tail, in position 871 on the U.S. Top Grossing list, an app still makes over $700 in revenue per day. That’s almost $260,000 per year. Even number 1,908 on the U.S. Top Grossing list makes over $100,000 per year.

His chart is based on the sales data from Marco Arment.

Filip Radelić:

Seems like a very optimistic approximation. I’ve seen apps around top 870 grossing with much, much less than $700/day.

Charles Perry (tweet):

I’ve gotten some feedback from readers asking how valid my extrapolated data is. Some have pointed out that I’m working with a limited data set from only one app that might not hold for all apps.


While the the exact revenue figures that I cited in The Shape of the App Store may be off little, it seems likely that they are at least in the right ballpark. They may even be somewhat conservative estimates if Manual’s revenue figures are to be believed.


Nate Cook:

We can easily access any values we’ve created in our context using subscript notation on both JSContext and JSValue instances. JSContext requires a string subscript, while JSValue allows either string or integer subscripts for delving down into objects and arrays:

Swift doesn’t support the subscript notation, though.

With a JSValue that wraps a JavaScript function, we can call that function directly from our Objective-C/Swift code using Foundation types as parameters. Once again, JavaScriptCore handles the bridging without any trouble[…]


There are two main ways of giving a JSContext access to our native client code: blocks and the JSExport protocol.


Since blocks can capture references to variables and JSContexts maintain strong references to all their variables, some care needs to be taken to avoid strong reference cycles. Avoid capturing your JSContext or any JSValues inside a block. Instead, use [JSContext currentContext] to get the current context and pass any values you need as parameters.