Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Launch Arguments - the mysteries

Marin Usalj
November 08, 2016

Launch Arguments - the mysteries

A talk on launch arguments in iOS / OSX environments.
Uncovers some undocumented behaviors and advanced usage.

Marin Usalj

November 08, 2016
Tweet

More Decks by Marin Usalj

Other Decks in Programming

Transcript

  1. May 15, 2017 | Marin Usalj
    Launch
    argumentsthe mysteries

    View Slide

  2. May 15, 2017 | MARIN USALJ
    @supermarin
    supermar.in
    Marin Usalj

    View Slide

  3. May 15, 2017 | MARIN USALJ
    Author of Alcatraz, xcpretty

    View Slide

  4. May 15, 2017 | MARIN USALJ

    View Slide

  5. May 15, 2017 | MARIN USALJ
    Agenda

    View Slide

  6. May 15, 2017 | MARIN USALJ
    Process Arguments
    Agenda

    View Slide

  7. May 15, 2017 | MARIN USALJ
    Process Arguments
    Advanced usage
    Agenda

    View Slide

  8. May 15, 2017 | MARIN USALJ
    Process Arguments
    Advanced usage
    Gotchas
    Agenda

    View Slide

  9. Process arguments

    View Slide

  10. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  11. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  12. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  13. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  14. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  15. May 15, 2017 | MARIN USALJ
    $ ls -la
    $ git commit -a -m 'yolo'
    Process arguments

    View Slide

  16. May 15, 2017 | MARIN USALJ
    Used by exec() family of functions (execve on OSX)
    Process Arguments

    View Slide

  17. May 15, 2017 | MARIN USALJ
    Used by exec() family of functions (execve on OSX)
    Launching binaries, scripts with #!
    Process Arguments

    View Slide

  18. May 15, 2017 | MARIN USALJ
    Used by exec() family of functions (execve on OSX)
    Launching binaries, scripts with #!
    In C-family of languages, main(argc, argv)
    Process Arguments

    View Slide

  19. May 15, 2017 | MARIN USALJ
    +(id)launchParametersWithSchemeIde
    ntifier:
    launcherIdentifier:
    debuggerIdentifier:
    launchStyle:
    runnableLocation:
    debugProcessAsUID:
    workingDirectory:
    commandLineArgs:
    environmentVariables:
    architecture:
    platformIdentifier:
    buildConfiguration:
    buildableProduct:
    Launching, Xcode style
    deviceAppDataPackage:
    allowLocationSimulation:
    locationScenarioReference:
    routingCoverageFileReference:
    enableOpenGLFrameCaptureMode:
    enableOpenGLPerformanceAnalysisMo
    de:
    simulatorIPhoneDisplay:
    simulatorIPadDisplay:
    debugXPCServices:
    additionalXPCServicesToDebug:
    internalIOSLaunchStyle:
    internalIOSSubstitutionApp:
    launchAutomaticallySubstyle:

    View Slide

  20. May 15, 2017 | MARIN USALJ
    Demo ⏲

    View Slide

  21. May 15, 2017 | MARIN USALJ
    There are a number of options that can be
    passed into a target’s scheme to enable useful
    debugging behavior, but like a fast food secret
    menu, they’re obscure and widely unknown.
    MATTT THOMPSON, NSHIPSTER

    View Slide

  22. May 15, 2017 | MARIN USALJ
    How does
    this work?

    View Slide

  23. May 15, 2017 | MARIN USALJ
    In most programming environments, you handle arguments by
    yourself
    How does this
    work?

    View Slide

  24. May 15, 2017 | MARIN USALJ
    In most programming environments, you handle arguments by
    yourself
    Bash: getopt, getopts
    How does this
    work?

    View Slide

  25. May 15, 2017 | MARIN USALJ
    In most programming environments, you handle arguments by
    yourself
    Bash: getopt, getopts
    Ruby: OptionParser (and n^2345 others)
    How does this
    work?

    View Slide

  26. May 15, 2017 | MARIN USALJ
    In most programming environments, you handle arguments by
    yourself
    Bash: getopt, getopts
    Ruby: OptionParser (and n^2345 others)
    Python: argparse
    How does this
    work?

    View Slide

  27. May 15, 2017 | MARIN USALJ
    How does this
    work?

    View Slide

  28. May 15, 2017 | MARIN USALJ
    In Cocoa, there's
    a little bit of

    View Slide

  29. May 15, 2017 | MARIN USALJ
    Arguments are parsed by Cocoa
    Parsing in Cocoa

    View Slide

  30. May 15, 2017 | MARIN USALJ
    Arguments are parsed by Cocoa
    Injected on top of NSUserDefaults
    Parsing in Cocoa

    View Slide

  31. May 15, 2017 | MARIN USALJ
    Arguments are parsed by Cocoa
    Injected on top of NSUserDefaults
    No need to store a value into NSUserDefaults to read it from args
    Parsing in Cocoa

    View Slide

  32. May 15, 2017 | MARIN USALJ
    Arguments are parsed by Cocoa
    Injected on top of NSUserDefaults
    No need to store a value into NSUserDefaults to read it from args
    Anything stored in NSUserDefaults can be overridden
    Parsing in Cocoa

    View Slide

  33. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    app

    View Slide

  34. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app
    conference = NSSpain
    speaker = Marin

    View Slide

  35. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app Launch args
    conference = SwiftSummit
    conference = NSSpain
    speaker = Marin

    View Slide

  36. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app Launch args
    conference = SwiftSummit
    conference = NSSpain
    speaker = Marin
    objectForKey: "speaker"

    View Slide

  37. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app Launch args
    conference = SwiftSummit
    conference = NSSpain
    speaker = Marin
    objectForKey: "speaker"
    "Marin"

    View Slide

  38. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app Launch args
    conference = SwiftSummit
    conference = NSSpain
    speaker = Marin
    objectForKey: "conference"
    objectForKey: "speaker"
    "Marin"

    View Slide

  39. May 15, 2017 | MARIN USALJ
    NSUserDefaults
    lookup
    NSUserDefaults
    app Launch args
    conference = SwiftSummit
    conference = NSSpain
    speaker = Marin
    objectForKey: "conference"
    "SwiftSummit"
    objectForKey: "speaker"
    "Marin"

    View Slide

  40. May 15, 2017 | MARIN USALJ
    What do I do
    with this?

    View Slide

  41. May 15, 2017 | MARIN USALJ
    Changing app
    behavior without
    recompiling

    View Slide

  42. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  43. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  44. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  45. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  46. May 15, 2017 | MARIN USALJ
    Lyft's use case
    ? ? ? ? ? ? ? ?

    View Slide

  47. May 15, 2017 | MARIN USALJ
    First approach: UIAutomation with a hidden server selector
    Bring up UI, type URI letter by letter
    Lyft's use case

    View Slide

  48. May 15, 2017 | MARIN USALJ
    First approach: UIAutomation with a hidden server selector
    Bring up UI, type URI letter by letter
    Lyft's use case

    View Slide

  49. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  50. May 15, 2017 | MARIN USALJ
    Lyft's use case

    View Slide

  51. May 15, 2017 | MARIN USALJ
    Recompile the app with hardcoded server address
    Given each compilation is ~5 minutes, this would waste at least 50 CI
    minutes for each developer push.
    Recompile?

    View Slide

  52. May 15, 2017 | MARIN USALJ
    Inject a file in the bundle after compilation
    Almost a viable solution, requires adding specific code for reading the
    bundle and overriding our servers.
    Inject a file?

    View Slide

  53. May 15, 2017 | MARIN USALJ
    Launch the app with arguments overriding server endpoints
    Challenge: server environment stored as a nested Dictionary
    More than one endpoint to override (analytics for example)
    Launch arguments?

    View Slide

  54. May 15, 2017 | MARIN USALJ
    "navigation": "Waze",
    "servers": {
    "api": "https://api.dev.lyft.com",
    "analytics": "https://analytics.dev.lyft.com"
    }
    Launch arguments?

    View Slide

  55. Advanced usage

    View Slide

  56. May 15, 2017 | MARIN USALJ
    $ lyft -servers.api "http://..." \
    -servers.analytics "http://..." \
    Key paths?

    View Slide

  57. May 15, 2017 | MARIN USALJ
    $ lyft -navigation Waze -servers '{ "foo": "bar" }'
    JSON?

    View Slide

  58. May 15, 2017 | MARIN USALJ
    Quiz ⏲

    View Slide

  59. May 15, 2017 | MARIN USALJ

    View Slide

  60. May 15, 2017 | MARIN USALJ

    View Slide

  61. May 15, 2017 | MARIN USALJ
    $ lyft -servers '{
    api = https://api.staging.lyft.com;
    analytics = https://analytics.staging.lyft.com;
    lastOpened = 2016-09-18T01:29:01Z;
    }' -conference FrenchKit -speaker 'Marin Usalj'
    NeXTSTEP plists

    View Slide

  62. May 15, 2017 | MARIN USALJ
    $ lyft -servers '{
    api = https://api.staging.lyft.com;
    analytics = https://analytics.staging.lyft.com;
    lastOpened = 2016-09-18T01:29:01Z;
    }' -conference FrenchKit -speaker 'Marin Usalj'
    NeXTSTEP plists

    View Slide

  63. May 15, 2017 | MARIN USALJ
    $ lyft -servers 'yolo'
    Built in XML reader
    1. Try to parse XML
    from 'yolo'
    2. Try to parse Plist
    from 'yolo'
    3. Just String('yolo')

    View Slide

  64. May 15, 2017 | MARIN USALJ
    $ lyft -servers 'yolo'
    Built in XML reader
    1. Try to parse XML
    from 'yolo'
    2. Try to parse Plist
    from 'yolo'
    3. Just String('yolo')

    View Slide

  65. May 15, 2017 | MARIN USALJ
    $ lyft -servers 'yolo'
    Built in XML reader
    1. Try to parse XML
    from 'yolo'
    2. Try to parse Plist
    from 'yolo'
    3. Just String('yolo')

    View Slide

  66. Gotchas

    View Slide

  67. May 15, 2017 | MARIN USALJ
    Overwriting values after launch won't work after app launch
    Watch out on places where you're reading / writing to
    NSUserDefaults
    Gotchas

    View Slide

  68. May 15, 2017 | MARIN USALJ
    UserDefaults is a key-value Store with String keys
    Value types: String, Data, Number, Date, Array, and Dictionary
    Gotchas

    View Slide

  69. May 15, 2017 | MARIN USALJ
    open func string(forKey defaultName: String) -> String?
    open func array(forKey defaultName: String) -> [Any]?
    open func dictionary(forKey defaultName: String) -> [String : Any]?
    open func data(forKey defaultName: String) -> Data?
    open func stringArray(forKey defaultName: String) -> [String]?
    open func integer(forKey defaultName: String) -> Int
    open func float(forKey defaultName: String) -> Float
    open func double(forKey defaultName: String) -> Double
    open func bool(forKey defaultName: String) -> Bool
    open func url(forKey defaultName: String) -> URL?
    UserDefaults
    helpers

    View Slide

  70. May 15, 2017 | MARIN USALJ
    /*!
    -integerForKey: is equivalent to -objectForKey:,
    except that it converts the returned value to an
    NSInteger. If the value is an NSNumber, the result of -
    integerValue will be returned. If the value is an
    NSString, it will be converted to NSInteger if possible.
    If the value is a boolean, it will be converted to
    either 1 for YES or 0 for NO. If the value is absent or
    can't be converted to an integer, 0 will be returned.
    */
    Gotchas

    View Slide

  71. May 15, 2017 | MARIN USALJ
    XML tags
    CoreFoundation
    type
    XML Tag Storage format
    CFString UTF-8 encoded string
    CFNumber , Decimal string
    CFBoolean , No data (tag only)
    CFDate ISO 8601 formatted string
    CFData Base64 encoded data
    CFArray Can contain any number of child elements
    CFDictionary Alternating tags and plist element tags

    View Slide

  72. May 15, 2017 | MARIN USALJ
    Thanks
    LYFT, IDA & BEREN

    View Slide

  73. May 15, 2017 | MARIN USALJ
    We are hiring!

    View Slide

  74. May 15, 2017 | MARIN USALJ
    https://developer.apple.com/library/ios/recipes/xcode_help-scheme_editor/Articles/
    SchemeRun.html
    https://en.wikipedia.org/wiki/Property_list
    http://linux.die.net/man/2/execve
    http://nshipster.com/launch-arguments-and-environment-variables/
    http://useyourloaf.com/blog/using-launch-arguments-to-test-localizations/#disqus_thread
    http://www.manpagez.com/man/3/execv/
    References

    View Slide