Tuesday, May 31, 2016

NSDecimalNumber and unsignedIntegerValue

So, if you have an NSDecimalNumber and you want to get the unsigned integer equivalent of it, you'd do [nsdn unsignedIntegerValue], right?

Wrong. Or, at least, risky.

I hit a bug in NSDecimalNumber this week, and I thought I'd share it as a playground, which you can download or read, but I'll summarize here.

Essentially, if you have an NSDecimalNumber containing a real number with a large mantissa and you call unsignedIntegerValue on it, you may get zero instead of the nearest integer. I assume it's a bug, rather than a design decision, but it's definitely risky to rely on unsignedIntegerValue here. If you  convert the value yourself (e.g. call floor(nsdn.doubleValue)) you'll be much better off.

I've filed a radar.

Tuesday, January 12, 2016

Opening App Transport Security failures in Safari

One of my client projects is an iOS application which, like many iOS Applications, has an embedded web view, which it uses in this case to display help content from the web. Because this app targets iOS 7.x as a baseline, it uses UIWebView instead of, say, SFSafariViewController.

The help content is part of the company's website, and the web page footer has social media links, and some of these links, if you clicked on them, wouldn't load.

Initially, I thought this might be because of the target="_blank" attribute, which has been a problem with UIWebView in the past, so I built a UIWebViewDelegate that would inject a little bit of JavaScript to remove the targets. It didn't work. So I changed the JavaScript to set the target to "_self". Still didn't work:

- (void)webViewDidFinishLoad:(UIWebView *)webView
    NSString *injectedJavascript = @"function "
      "AppPrefix_Injected_suppressBlankTargets() {\n"
      "  var links = document.getElementsByTagName('a');\n"
      "  var hrefs = [];\n"
      "  for( index = 0; index < links.length; index++ ) {\n"
      "    var link = links.item( index );\n"
      "    if( link.getAttribute( 'target' ) == '_blank' ) {\n"
      "      link.setAttribute( 'target', '_self' );\n"
    "      hrefs.push( link.outerHTML );\n"
      "    }\n"
      "  }\n"
      "  return hrefs.join();\n"
    NSString *result = [webView 
    DLog( "Injected javascript to suppress blank targets on links: %@", result );

Having failed on two assumptions, I realized that I should verify my assumption instead, and implemented webView:didFailLoadWithError, which quickly showed me that the actual problem was App Transport Security.

The social media links? Some of them are HTTP rather than HTTPS, and those ones won't load because App Transport Security doesn't like it. That left options.

Disable App Transport Security?
I don't like going this route until I have to.  I don't want to whitelist certain sites because the social media links might lead to other sites which would also need to be whitelisted and then eventually you just end up disabling app transport security anyway.

Open ATS Failures in Safari
What I ended up doing instead is listening for errors (webView:didFailLoadWithError) and then check the error. If it was an app transport security failure, pull the URL out of NSError's userInfo and then open that link in mobile safari instead.

It's fairly straightforward. Write a UIWebViewDelegate like this:

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSURL *failedUrl = [self parseATSError:error];
    if( failedUrl != nil ) {
        DLog( "ATS Failure, opening in Safari: %@", failedUrl );
        [[UIApplication sharedApplication] openURL:failedUrl];
    } else {
        DLog( "Failed to load, with non-ATS error: %@", error );

- (NSURL *)parseATSError:(NSError*)error {
    if( error == nil )
        return nil;
    if( ![error.domain isEqualToString:NSURLErrorDomain] )
        return nil;
    if( error.code != -1022 )
        return nil;
    NSString *url = error.userInfo[ NSURLErrorFailingURLStringErrorKey ];
    return [NSURL URLWithString:url];

This seems to work. So if you're using an UIWebView and running afoul of App Transport Security, maybe this will help you.

Tuesday, January 5, 2016

AppStore Release Joy

After what felt like an eternal delay, one of the my client's apps has finally gone live in the App Store. It is always nice when something you write goes live, but somehow the app store process, painful though it may be, makes the final victory of "Hey, there's my App, live in the App Store" feel that much sweeter.

I've already seen some press for the app (and related wearables), so it's already somewhat promising, but it'll be interesting to watch it grow.

Thursday, November 5, 2015

Fabric / Crashlytics ADD in Images

Remember how I commented that Crashlytics' daily email was so focused on the daily delta that it lacked a sense of the overall trends?

Here's two daily emails back to back. October 30th:

October 31st:

App name pixelated because I haven't cleared sharing this information, so I'm sharing it without the identifiable information.

These kinds of transitions, from "growing like crazy" to "growth slows" and back are a daily occurrence which totally obscures any real trends about how many users are actually using your app.

Tuesday, October 27, 2015

GWT Plugin Still Not Ready for Eclipse 4.5?

Eclipse Mars / v4.5 was released June 24, 2015. The Google Plugin for Eclipse 4.5 has not yet been released. If you go to the Google Plugin for Eclipse quickstart page, you can see that it's still showing links for Eclipse 4.4, 4.3 and 4.2 / 3.8.

In essence, if you'd like to use GWT and you want to use the latest Eclipse, there's no officially supported option nearly four months later.

If you do a little searching, you'll find a few threads on the subject, :

A friend tried Eclipse 4.5 and the Google Plugin for Eclipse 4.4 together and hit a NoClassDefFound error for Java2HTMLEntityReader. A quick search found that it was a bug, but that raises further questions about a plugin fork, which looks like it might have been around since 2013. It looks like there's a lot of work underway.

Ultimately, between this and some of the posts about GWT 2.8, this adds to my long-growing sense that GWT is stagnating. It hasn't descended into a terrible state yet by any means. It's quite usable for existing projects. Still, I wouldn't recommended it for a new project, and I'd recommend that people using it on existing projects start thinking about the long-term plan for their projects and consider a plan to move away from GWT at some point and how to manage that transition.

Thursday, October 22, 2015

Fabric / Crashlytics Growth ADD

Crashlytics' / Fabric has a daily email which gives you a sense of recent crashes, and also some basic stats.  It's useful, but they don't seem to consider that there can be a fair amount of day-to-day variance and attempt to smooth that out and give you a sense of real trends. Instead, everything is about yesterday's change:

  • Day N:
    • New sessions up 20%!
    • Your app is on fire!
    • Seek investment immediately!

  • Day N+1:
    • New sessions down 15%!
    • Your app is beginning to stagnate!
    • Oh noes!
I captured images from two back-to-back emails as a good example.

Thursday, September 24, 2015

Searching for Android Documentation in Dash

Android developers: are you using Kapeli's Dash to read Android docs on a Mac? Want to be able to search for inherited methods without hitting "expand all" first? Request it!