The most annoying bug - Or Why Fast Lists 2.0 is late

TL;DR - Warning, long rambling description of the winding path of development of version 1.79

Trying to be bug free for iOS 5 and 6 users was harder than expected caused by a mixture of bad luck, Apple's bugs and my own mistakes. I felt a need to write it, you shouldn't feel the need to read it!

Background

Fast Lists was originally released support iOS 5 and later so that I could take advantage of the latest features when I initially developed it. None of the new iOS 6 features were adopted but when iOS 7 was announced some of the features were things that I really wanted to use, particularly the new design which I wanted to properly support along with Dynamic Text and the ability to change the size of the text with the system settings. This version will be Fast Lists 2.0

While the Apple App Store knows about the compatibility of updates with older versions and won't let users update to a version not built for that platform there is no way for any further updates to be made (without it being an update to the users of the latest version too).

After version 1.60 I was receiving two forms of feedback about issues:

  1. Crash reports including a stacktrace when the app actually crashes (these are received automatically from users who have not disabled them "Usage reporting" in the Settings.
  2. In the event of some error conditions that I have foreseen as possible (although unlikely) Fast Lists asks the user to send me some information by email. The email is largely pre-composed with some information about the error but also gives the opportunity to provide additional information AND importantly allows me to respond to the email and ask the user further questions about what happened and potentially offer assistance at times. For serious errors normally where there is risk of data corruption Fast Lists will quite (via calling abort) rather than risk continuing in an inconsistent state.

Both mechanisms have different advantages, the crash reports are automatic and can often give very exact locations where the crash occurs. The email allows follow up with the user about what was happening but provides less technical information and only a small proportion of those who suffer from issues send the email.

The Plan

I decided that the long term cost of maintaining compatibility and two code paths for all areas where iOS 7 features would not be worth it given the speed of adoption of new iOS versions historically. So from the time of announcement I started working on a branch intended to make use of the iOS 7 features. Despite this decision to go iOS 7 only for future versions I didn't want to leave existing users who couldn't or didn't want to update with a poor product so I was determined to crush all the bugs and at least leave a very stable version.

The split actually started with the 1.60 release on 24th June 2013 which I was actually hoping might be the last release for iOS 5 and 6. As it has turned out there were actually another 14 releases after that before I could get to a position where I am happy to release the Fast Lists 2.0 update. 

The Reality

1.60 was a major change that removed the use of the Parse platform for logging because it had been bought by Facebook (see previous post). It also added the use of PLCrashReporter and JIRAMobileConnect as a partial replacement for Parse, specifically the crash logging which it did somewhat better than my previous solution although without logging some non-crashing errors.

This meant several latent issues were revealed that led to a further sequence of updates to fix issues that were revealed (some of which were caused by a mistake in the way I added the crash reporting). After that 1.60 release bugs were squashed one or two at a time and in parallel I was working on version 2.0 to properly adopt the new design and handling the variable sized text.

The software was improving and number of crashes falling until when iOS 7 was released I was getting a significant number of issues saving on that platform with an error regarding conflicts when there was actually no reason a conflict should have been reported. I was not able to reproduce the problem on my test systems.

1.73 - Xcode 5.0 and NSMergeByPropertyObjectTrumpMergePolicy

To resolve the problem of conflicts during saves I changed the mode of saving to specify that the current in memory version should be prioritised in the save (NSMergeByPropertyObjectTrumpMergePolicy) rather than raising an error on save problems. I also used Xcode 5 to build this version which turned out to be a mistake for several reasons. The most obvious reason was that this introduced the iOS 7 look and feel but without the proper modifications that I had made to make the design really work well with Fast Lists (I should have realised that this would happen and probably retained Xcode 4.6). The other reason was that this exposed me to a bug but it would be some time before I discovered that.

As soon as it hit the App Store I found that it seemed to have resolved the issues that I was having on iOS 7 unfortunately it became apparent over the few days after the release that I was now having problems while saving on iOS 5 and 6. Again I could not reproduce this locally and additionally I no longer had any iOS 6 devices with which to test.

1.74 - Xcode 5.01

This was a very quick release that wasn't a major change but used Xcode 5.01 to build in case it resolved the crash reports I was suffering from on iOS 5 and 6. I was only receiving crash reports initially and they hadn't isolated the issue, (although I hadn't realised it they were in fact referencing the location where I was aborting on serious errors after the users had been offered the option of emailing me). 1.74 didn't help at all.

The Assumption

Quite naturally I assumed that the small change that I had made in 1.73 at exactly the place in the code where I was now seeing errors was to blame. It is usually the change you make in the software that is to blame when a problem is introduced. So while I couldn't reproduce the problem I did the obvious next step and reverted the behaviour except for iOS 7 (where this problem wasn't happening and the previous problem seemed to be resolved). As it turned out this didn't actually help at all!

1.75 - Make NSMergeByPropertyObjectTrumpMergePolicy iOS 7 Only

By this time I had received some emailed error reports showing validation errors errors on iOS 6 were happening. The errors I received were like this:

FATAL ERROR
Error UUID: 1510B4F6-0E85-44D0-8DCC-2D5A269EA66A
App UUID: 3E982994-4315-4E76-BB21-6BDF25E37BC6
Error Message: "Apologies but it has not been possible to save your last change.  Please inform support@human-friendly.com about this issue with any information that you have about what caused it."Error Details:
Error Domain=NSCocoaErrorDomain Code=1570 "The operation couldn’t be completed. (Cocoa error 1570.)" UserInfo=0x1d849b70 {NSValidationErrorObject=<TopLists: 0x1c54cd70> (entity: TopLists; id: 0x1c588d20 <x-coredata:///TopLists/tB6F75849-4766-4605-BE60-8AFB2BBC95B22> ; data: {
    list =    (
    );
    name = nil;
    parent = nil;
}), NSValidationErrorKey=name, NSLocalizedDescription=The operation couldn’t be completed. (Cocoa error 1570.)}
Model: iPad
Platform:iPad2,2
Model: K94AP
SystemVersion: 6.0.1
App Version: 1.74
Bundle Version: 1.74
Free Disk space: 7329200KiB
Now this report is more useful than I had realised. I save the updates that I have made from many different areas of the code (every update from a new item, a name change, a deletion or even ticking or unticking a checkbox) but I should have taken the error at face value and looked for where toplevel lists (the only time parent should be nil) are saved and particularly at their creation to verify any potential sources of nil names and try to reproduce in the simulator but I focussed too much on the the idea that it was a Core Data problem.

1.76, (unreleased 1.77) and 1.78

These releases fixed a number of other issues (related dragging lists on iPads, iOS 7 layout issue, and a fix for deletions) and added a stacktrace to the emailed error reports. Then I had to wait for an email report with the new error information.

It finally arrived on 29th November (and actually it is the only emailed report form the 1.78 version I have received even now since 1.78 was released on 21st November) so I am very grateful to the reporter.

FATAL ERROR
Error UUID: F4935501-D278-46CE-8257-DADB5A3CD7FD
App UUID: 6B900CD9-7FD4-42A6-A9D9-D0DEBECA2F6E
Error Message: "Apologies but it has not been possible to save your last change.  Please inform support@human-friendly.com about this issue with any information that you have about what caused it."Error Details:
Error Domain=NSCocoaErrorDomain Code=1570 "The operation couldn’t be completed. (Cocoa error 1570.)" UserInfo=0x1ddad030 {NSValidationErrorObject=<TopLists: 0x1ddb9f50> (entity: TopLists; id: 0x1ddb3250 <x-coredata:///TopLists/tAC51B92C-A320-44BA-9D91-27EBA6E0C4322> ; data: {
    list =    (
    );
    name = nil;
    parent = nil;
}), NSValidationErrorKey=name, callStackAddresses=(0x35785 0x3565d 0x333f9 0x3664d0c5 0x3664d077 0x3664d055 0x3664c90b 0x3664ce01 0x3656b421 0x3472f6cd 0x3472d9c1 0x3472dd17 0x346a0ebd 0x346a0d49 0x382532eb 0x365b6301 0x2f823 0x2f7d8), NSLocalizedDescription=The operation couldn’t be completed. (Cocoa error 1570.), callStackSymbols=(
0  Fast Lists                          0x00035745 Fast Lists + 55109
1  Fast Lists                          0x0003565d Fast Lists + 54877
2  Fast Lists                          0x000333f9 Fast Lists + 46073
3  UIKit                              0x3664d0c5 <redacted> + 72
4  UIKit                              0x3664d077 <redacted> + 30
5  UIKit                              0x3664d055 <redacted> + 44
6  UIKit                              0x3664c90b <redacted> + 502
7  UIKit                              0x3664ce01 <redacted> + 488
8  UIKit                              0x3656b421 <redacted> + 5768
9  CoreFoundation                      0x3472f6cd <redacted> + 20
10  CoreFoundation                      0x3472d9c1 <redacted> + 276
11  CoreFoundation                      0x3472dd17 <redacted> + 742
12  CoreFoundation                      0x346a0ebd CFRunLoopRunSpecific + 356
13  CoreFoundation                      0x346a0d49 CFRunLoopRunInMode + 104
14  GraphicsServices                    0x382532eb GSEventRunModal + 74
15  UIKit                              0x365b6301 UIApplicationMain + 1120
16  Fast Lists                          0x0002f823 Fast Lists + 30755
17  Fast Lists                          0x0002f7d8 Fast Lists + 30680
)}
Model: iPod touch
Platform:iPod4,1
Model: N81AP
SystemVersion: 6.1.5
App Version: 1.78
Bundle Version: 1.78
Free Disk space: 17439224KiB
I could copy the stacktrace into the crash report that matched this incident (identified by the timing of the reports) to symbolicate it. The result was clear that this was happening when the toplevel  '+' button was being used to create new top level lists.

With that information and the validation errors about the nil name I tried it in the simulator and managed to reproduce the issue. It proved to be that instead of enabling the text input field when the '+' was pressed with no name in the field it was trying to create the list with a nil name. This is the relevant function:

-(void)cellButtonAdd:(UIButton *) addButton
{
    if([[newListCell.nameField text] isEqual:@""])
    {
        [newListCell.nameField becomeFirstResponder];
        [[HFUsageLogger getSharedLogger] incrementCounterForName:@"topListCellButtonAddEmptyField"];
        return;
    }
    // Create a new instance of the entity managed by the fetched results controller.
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    TopLists *newTopList  = (TopLists *)[NSEntityDescription insertNewObjectForEntityForName:@"TopLists" inManagedObjectContext:context];
       
    newTopList.name = [[newListCell nameField]text];
    newTopList.newItem = YES;
    [newListCell.nameField resignFirstResponder];
    newListCellString = @"";
    newListCell.nameField.text = @"";
    NSIndexPath * selected = [self.tableView indexPathForSelectedRow];
    if(selected)
        [self.tableView deselectRowAtIndexPath:selected animated:YES];
    [newTopList save];
    if(addButton)
    {
        [[HFUsageLogger getSharedLogger] incrementCounterForName:@"topListCellButtonAddSucceeded"];
    }
    else
    {
        [[HFUsageLogger getSharedLogger] incrementCounterForName:@"topListReturnKeyAddSucceeded"];
    }
}
[newTopList save] eventually calls [managedContext save] which is when the error occurs.

This code is actually correct but it was clear that the check at the beginning was not working:
if([[newListCell.nameField text] isEqual:@""])
In the debugger I could clearly see[that `[newListCell.nameField text]` was returning nil (which is clearly not equal to the empty string @""). This is not the correct behaviour; the UITextField class reference for the text says: This string is @"" by default. Testing on iOS 7 shows the correct behaviour (as do iOS 5 and 6 when the app is built with Xcode 4).

Once I had found this the fix was a fairly simple replacement of the test:
if([[newListCell.nameField text] length ] == 0)
In Objective C if you send a message to nil it is safe but does nothing except return nil (0) so whether we have an empty string or a nil value instead of the string this test handles it correctly.

Conclusion

I should have assumed less about the bug and tested more on the simulator (as I don't currently have an iOS 6 device), maybe I could have found it sooner. However I was VERY unlucky to hit a bug affecting a particular combination of build tool and iOS version at exactly the time I made a change that affected the exact functionality where I was seeing errors.
Apologies for such a long and dull post but I needed to get it down.

Useful SVG to iOS icons tip using Inkscape

I found this very useful blog post with a commandline for batch creating icons from an SVG file.

ruby -e '[58,120,29,40,80,76,152,1024].each { |x| `/Applications/Inkscape.app/Contents/Resources/bin/inkscape --export-png icon#{x}.png -w #{x} icon.svg` }'

I also want to try to expand it to be able to produce launch screens in the same way by doing an aspect fit to the right shape and produce all those rectangular sizes. I'll post again if I figure it out.
I'm also considering looking at the Cairo library to develop an OS X tool to do this easily (and possibly also create an XCAssets file). If this app would interest you let me know if you would be sufficiently interested to play $10 for it.

This documentation for Inkscape should give me the necessary parameters to do this with a simple script.

Update - See this Github repo for a fuller implementation

SVGtoIcons is still pretty barebones with no commandline support and hardcoded file names but it should be pretty easy to modify to do what you need. It is only a page and a half of Ruby. I'll write a proper blog post about it soon.


Human Friendly has stopped using Parse

What is Parse?

Parse is a convienient online database service with some additional useful features. It also has a software library that can be included in apps to enable easy use from inside apps for online storage.  It also has additional features but we didn't use many of them deliberately so that we were not locked in too tightly and had the flexibility to move.  These features that we didn't use included user accounts, Facebook integration, Push notifications and probably a good number more.

What Did Human Friendly Used Parse For?

As described in the Privacy Policy we used it for several things:

  1. Anonymous usage logging.  Essentially how many times different features were clicked on, how many lists and items you have.  That sort of thing should enable a better understanding and improvement of the app to support the existing use better.
  2. Error recording.  This was both for crashes (although it may not have covered all scenarios) and some unexpected conditions that may need attention even if they did not lead to an immediate crash.  Again this is directly to enable Human Friendly to improve the Fast Lists app.
  3. Promotional codes.  I could generate promotional codes that I could email to enable the in-app purchase features for no cost.  The entitlements in terms of how many devices they could activate were stored in Parse and it counted down their use of them.  This was a one time check when using the Promotional code and it did not track/monitor or control further use of the feature.

All this used the simple JSON object store features of Parse.

    Why Did We Stop Using Parse?

    Parse was recently acquired by Facebook.  I don't trust Facebook with much of my data and I certainly didn't want to trust them with any of Human Friendly's customer's data.  Facebook are an especially big risk as they are likely to be able to de-anonymise data if they wanted to by cross referencing the devices or IP addresses used to access the service with the users they know about accessing their website or the Facebook app.  Now I want to be clear that I am not accusing Facebook or Parse of doing this or having current plans to do this but the fact that they could do it if they wanted to is a threat.

    What Steps Did We Take?

    Crash Reporting

    The most critical part of the data is the crash reporting and that was sort of a hack anyway and I knew better solutions were available.  I may do a further post on the issue but many of the services had privacy policies that I did not like including that they could gather anonymous usage logs for their purposes.  The data from Fast Lists is not really personal but again when aggregated with other data (outside of Human Friendly's control) could have included personal information.

    The crash reporting solution that I have chosen is Jira Mobile Connect combine with a JIRA server that is hosted at Human Friendly's headquarters.  JIRA is a software issue tracking tool and when a crash occurs it creates a new issue and most importantly gives me access to the crash report which can be symbolicated in Xcode to see exactly what line was running at the time of the crash (although the bug is sometimes somewhere else).  The traffic is low, often less than one crash per day although it has been higher with the 1.66 release of the software.

    From version 1.60 the new crash reporting system was in place and use of Parse disabled.  Now actually due to a set up error on my part the changes have actually triggered a number of crashes although those have been fixed in subsequent versions and the easier access to the better crash reporting that we now have has enabled us to do a better job of pinpointing other crashes which we have been fixing one by one through the 1.6x releases.

    General Logging and Promocodes

    These are currently disabled.  We will probably host a replacement on a virtual/cloud host that we control and is probably going to be hosted on Digital Ocean although it may be hosted with our current webserver on Rackspace (No problems with Rackspace but Digital Ocean offer much more for similar prices).

    Benefits of the Change

    While some ease of use and convenience has been lost there has been some substantial benefits to the migration.

    • Better crash reports that can be more easily acted upon to improve the software.
    • Reduced application size.  The current 1.67 release of Fast Lists is only 725KB in the app store but the 1.51 version with the Parse libraries was about 5MB or nearly seven times the size.  This means faster updates, less wasted space on your devices and may enable the app to start faster and use less memory while running.

    Turning Off Parse

    Even though version 1.60 was released a little over three weeks ago (on 24th June) not everyone updates their apps immediately on release so there are still a number of users on version 1.51 or earlier.  While we have done some brief testing of the stability of 1.51 when it is unable to contact the Parse server we haven't done long term testing so there is a possibility that disabling the server could cause issues for some users.  Because of that we have waited until the number of accesses to Parse has fallen to much less than 100 per day (from well over a thousand) before downloading all data, deleting it from the Parse servers and deleting the app from their system.

    All data is now removed from Parse/Facebook

    Fast Lists Version 1.66 Crashes Update

    Update: Version 1.67 which may fix this issue was made available at about 5am UTC on 18th June.  Please update if you haven't already.

    Update2: No crashes in version 1.67 up to this point (about 32 hours since release).  Looking good so far.

    The Problem

    When the 1.66 version was initially posted I received a sudden flurry (15 apparently from four or five different users) of crash reports within the first 12 hours of release coming from the deletion confirmation that I put in place.  

    My Actions

    I tested again on my device and could not reproduce the problem.  Reviewing the code again I spotted what seemed to be a potential cause that may have caused issues if the problem occurred on the deletion of the first (topmost) list.  This one character fix (changing greater than to greater than or equal) was submitted that first evening to Apple for review as version 1.67.  The status changed to "In Review" at a little after 7pm yesterday (Tuesday) so I expect it should be available soon and I hope that it will resolve all these crashes.

    I also put a note on the Human Friendly website asking for information both on the front page and the support page.

    Until I started writing this blog post there had been no further crash reports since 6 am yesterday (40 hours ago) although since starting this post another four crash reports have arrived apparently all from one user.

    Help request

    If you have suffered a crash in Fast Lists please email me and let me know what was happening at the time and any details that you can remember.  Email me about this or any other issue at support@human-friendly.com

    This case more particularly than others I am interested in information as I haven't been able to reproduce the problem on my own test devices which is very valuable to confirm the details of the problem (especially if I can observe it in the debugger) and to confirm that the fix made really fixes the issue.

    Apologies

    To all those who have suffered crashes I send my apologies.  It isn't acceptable performance from my software I expect it to be almost entirely crash free.

    Other Known Issues

    On occasions there is an issue loading data from the Core Data system that Apple provides on their computing devices.  When this happens (especially when trying to update the list) Fast Lists crashes rather than continue operating in way that may lead to your changes not being properly saved.  When next started Fast Lists will try to verify all the data and ensure a consistent state.

    I suspect that this is when an item is being edited and it is deleted underneath it.  I think it only happens on the iPad and I think I have identified the most significant location where this happens and I am preparing a 1.68 version to submit when 1.67 is released by Apple.  Apologies for all these updates.

    Are you breaching Open Source Licenses accidentally?

    MIT Licenses and Requirements in Mobile Apps

    I am not a lawyer, this is not legal advice I only read the plain text of licenses and try to comply.

    TL;DR

    Much open source licensed software even permissive licenses like the MIT license and the Apache license require a copyright notice to be distributed with derivative works (although the Apache licences definition of derivative doesn't include where linked by name).  In the case of mobile apps you should at least be including the license text in the bundle and to comply with the spirit of the license I think that you should be exposing it to the end user through the interface.

    If your app uses PLCrashreporter, Crashlytics, HockeyApp or uses any open source licenses and you haven't carefully thought about presenting those licenses to the user you should read the long version.

    Background

    I developed the Fast Lists app for the iPhone and iPad.  It is a fairly simple app focussed on use for check lists, shopping, packing, emergency services divers checklists or really anything that you can think of.

    Until version 1.60 is released I was using Parse for anonymous logging (including a self implemented crash reporting system) and for managing promotional in-app upgrade codes.  However when Facebook bought Parse I felt that I needed to move away from their services [I may post separately].  I can live without the anonymous logging and promocodes temporarily but I didn't want to be without crash logging as Apple only seems to provide reports when crashes reach a certain frequency that Fast Lists was not reaching

    I looked at a number of hosted and self hosted solutions including:

    • Crashlytics
    • Flurry
    • HockeyApp
    • Quincy Kit.net
    • PLCrashReporter (and writing my own server)
    • JIRA and JIRA Mobile Connect Plugin

    In the end I picked JIRA largely for reasons unrelated to to this post.

      The Problem

      Most (all?) of these are based on PLCrashReporter and potentially other Open Source software and as far as I know they all comply with the license.  However none of these take explicit steps to bring to your attention your obligations as a downstream user.  At the VERY least you need to be including a copy of the Licence and copyright notice within your app bundle and I think to comply with the intent of the licenses you should be exposing them to the user in some way as while I know that you can ask iTunes to show the .ipa in finder and then you can unzip and explore it I don't think many users would do that.

      MIT License

      The MIT License PLCrashReporter mostly uses says:

      Copyright (c) <year> <copyright holders>

      Permission is hereby granted ...[lots of good stuff do what you want]...

      The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

      [Legalese to say no warranty]

      So if a substantial portion e.g. (the PLCrashReporter library) is included in your app so must the permission and copyright notice.  For this as I read it including in the bundle with no user accessibility may be legal.

      The Apache License

      The PLCrashReporter uses the protobuf-c library which is licensed under the Apache License version 2.0.  This is longer and more detailed and makes clear than simply linking does constitute the creation of a derivative work.  However by including the library in your application you not only link to it but distribute the library.  Clause 4 of the license is about Redistribution and part 4 says:

      If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.

      Now it may be possible to get around this in a couple of ways, firstly possibly intentionally neither the PLCrashReporter or the protobuf-c one seem to have a NOTICE file so this section may not apply although the material in the PLCrashReporter LICENSE file is similar to that which I would expect in a NOTICE file.  Secondly even if NOTICE file existed you might just be able to place it within the app bundle under the "within a NOTICE text file distributed as part of the Derivative Works" option only if you did not otherwise have third party licenses appearing within the display generated by the app.

      However even if you use the lack of the NOTICE file part 1 of the same clause says:

      You must give any other recipients of the Work or Derivative Works a copy of this License; and

      So you must at least include the copy of the LICENSE file inside your bundle and not giving them the opportunity to access it would to me seem to break the spirit of the license if not quite its precise language.

      How is this presented by service providers and downstream licenses?

      The closest of the commercial offers to making it clear was probably Crashlytics whose legal page has a link to "Open source licenses" that isn't buried in the text of a long legal document or in a sub-folder of a download.  It doesn't actually seem to be referenced from the legal document so it isn't completley apparent that it needs to be followed by downstream users.

      In fact when I queried Crashlytics about the open source license and the end user requirements and whether I needed to add a licenses section to my app (I'm lazy and I didn't want to spend the time including additional UI on iPhone and iPad) I got this response which I didn't find reassuring about the correctness of the approach although in practice it is probably valid:

      Joseph, great question!

      None of our customers, to my knowledge, has distributed our license with their app and we've seen no cause for alarm so far. That said, it might make sense for you to do so out of an abundance of caution if you are concerned.

      Hope this helps,

        Now I believe that following this advice would technically lead you to breaching at least two licenses. I think as you include the Apache licensed Proto-bufs in your bundle you are certainly distributing even if your app is not a derivative work.

        The Blame and What Should be Done Better

        I'm going to talk about PLCrashReporter because that is the specific software where I hit this issue but I really don't want to pick on them or be making a specific point about them.  Its really about mobile targeted open source.  I really appreciate the PLCrashReporter software that has been provided by the Plausible Labs and they have done nothing wrong but they could help the situation.

        App Developers

        Now we should all read every word of the legal documents we receive, read and understand the details of the licenses for all software we include in our apps so we all share some blame.  For now we need to not be lazy and actually add the UI to our apps to present these licenses (or write all the code ourselves)

        Open Source Library Developers

        I think that the source of the problem is that the original upstream projects set license terms without thinking about them.  I have the feeling that the PLCrashReporter developers don't really expect the license terms to be included with app store apps.  They just used the MIT license because it is standard and permissive.  I think that they should set out their expectations and guidance about how the license should be presented or bundled or possibly even better add additional terms allowing the license to be excluded from mobile apps (and possibly linked to from the developer's site or the app description).

        Now in many cases not thinking about how the documentation would be handled in mobile apps is completely understandable but they are the main target for some libraries such as this so it really should be considered.

        Commercial Services and Downstream Libraries

        The services and derived libraries should include in their user instructions the requirement to add the license to the end user's software bundle. They could even offer a convienience ViewController and Xib to present it (and other licenses if the user needs to show them too).  I think this is the place where the greatest responsibility lies.  These services largely have paying customers whose work is being put into some legal risk, they have a responsibility to their customers to explain what is necessary to comply with the upstream license and it should be in the main how to get started documentation not tucked away in the legal agreement.

        My Solution

        I implemented the license screen in the end.  I want to be squeaky clean.

        My current overall solution is using the JIRAMobileConnect and self hosting a starter licensed version of JIRA.

        You can find the open source code that I have used:

        • PLCrashReporter (not really modifed from the original).

        • JIRAMobile Connect iOS (small modifications from original to support embedding in Xcode project as subproject and git submodule - but that is another story).

        • MinimalGoogleToolbox is a hugely stripped down version of Google Toolbox For Mac extracting only a couple of text processing (particularly JSON) categories for use in my app without bloating the binary.  You could probably use the minimal version and then add other parts in if you wanted to.