AppDeveloperKit

Reusable, configurable Swift classes for iOS

Request an invite

AppDeveloperKit is a tool for iOS developers to assist in building re-usable, configurable class components. Properties are declared in classes and coded to affect appearance and behavior. The values for these properties are stored in a property list (plist) file. A macOS app provides a UI to edit these properties in real-time as an app is actively running on a device or simulator.

AppDeveloperKit is comparable to the use of @IBDesignable/@IBInspectable but can be used with all Swift classes (not just subclasses of UIView).

  • Edit the appearance/behavior of an app while it runs on a device or simulator.
  • Store property configuration in a plist file in your project.
  • Easily integrate with supplied iOS framework and a few lines of code.
  • Manage multiple projects/classes/properties with the macOS app UI.
  • Supported property types include UIColor, String, Bool, Double, Int.
  • Describe properties with JSON.
  • Library mode facilitates distribution of your configurable code via CocoaPods.

How it works

The AppDeveloperKit macOS app serves as the UI for the configurable properties that you use in your iOS Swift classes to control appearance and behavior.

Generated files

For each project, a pair of files are generated that you add to your iOS Compile Sources and Bundle Resources during project setup:

  • AppDeveloperKit.swift
    • A single Swift file that contains extensions for all configurable Swift classes specified in the UI.
    • Extensions contain an API interface to the AppDeveloperKit iOS framework that was installed as a Pod.
    • API supports property value fetches and live updates to a device or simulator.
  • AppDeveloperKit.plist
    • A single property list file that contains configuration info for all Swift classes and properties specified in the UI.
    • An iOS app fetches values from this file for these classes/properties using API calls in AppDeveloperKit.swift.

User interface

You use this interface to create and maintain:

  • Projects
    • A single local Realm database stores project names and pointers inside your project directories.
    • Project directories are where AppDeveloperKit.swift and AppDeveloperKit.plist are stored.
  • Class configurations
    • A entry in AppDeveloperKit.plist for each Swift class that contains one or more configurable properties.
    • Init/deinit code in AppDeveloperKit.swift as an extension for each of these Swift classes.
  • Properties
    • A entry in AppDeveloperKit.plist for each configurable property for a Swift class.
    • Framework API code in AppDeveloperKit.swift in the class extensions to control property initialization and live updates.

Live updates

The AppDeveloperKit macOS app can communicate with a device over Wi-Fi, Bluetooth or while tethered. It also works with the simulator.

Property changes in the UI are sent in real-time to the running iOS app to update appearance/behavior.

Revision control and maintenance

It is recommended that the generated files AppDeveloperKit.swift and AppDeveloperKit.plist be placed under revision control along with the rest of your iOS project. The plist file in particular contains all the configuration information for your project. The Realm DB is only used to point to these project plist files.

The macOS UI is not intended to provide general file management for your configurations. What does this mean as a practical matter?

  • There is not currently a mechanism to relocate configurations using the UI.
  • Changing the directory in the UI for an existing project will:
    • Read in a new configuration if the new directory contains a valid AppDeveloperKit.plist.
    • Start a new configuration (new plist file) if the new directory does not contain a valid AppDeveloperKit.plist.
    • In either case, all the current class configurations will be changed, but not lost - see Forget Project below.
  • If you wish to relocate a configuration (that should be under revision control), do so outside the UI and then update the directory for the project in the UI.
Forget Project

The iOS Project section in the UI has a Forget Project button. Clicking this button will only remove the project label and pointer to your project directory (where AppDeveloperKit.plist and AppDeveloperKit.swift are stored).

Using this feature is fairly benign. You can easily create a new entry for your iOS project and point it to an existing configuration.

Changing the directory of an existing project is similar to forgetting a project. You can easily undo this by changing the directory back again.

A typical workflow (after initial setup) might look like:

  • Add new classes and properties to macOS app UI. Establish initial property values.
  • Instrument iOS classes for new configurable properties.
  • Run the app and macOS app together.
  • Update/save properties in macOS app UI until app appearance/behavior is as desired.
  • Checkin changes to AppDeveloperKit.plist, AppDeveloperKit.swift

At the end of a workflow iteration, the iOS app is ready to operate independently of the macOS app.

I am looking for early testers for AppDeveloperKit. If you are an iOS developer who is interested, please contact me at feedback@appdeveloperkit.com

Scott Carter
www.linkedin.com/in/earlyrise

Setup

Getting started with AppDeveloperKit

Before you begin, please review the Copyright & Disclaimer.

AppDeveloperKit is in the Alpha testing stage. To install the AppDeveloperKit macOS app, please see the instructions sent to you with your invite.

The AppDeveloperKit iOS framework is currently available to be installed using CocoaPods.

A basic Podfile might look like:

platform :ios, '11.0'

use_frameworks!

source 'https://github.com/CocoaPods/Specs.git'

target 'MyAppTarget' do
pod 'AppDeveloperKit'
end

1. Add the following import to the top of AppDelegate.swift:

import AppDeveloperKit

2. Add a call to the AppDeveloperKit setup method at the point where you have finished launching:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

// Only Developer builds will enable live updates.

#if DEBUG

ADK_Config.shared().setup(enableLiveUpdates: true)

#else

ADK_Config.shared().setup(enableLiveUpdates: false)

#endif

return true

}

Perform some one-time setup for your iOS project in the macOS app.

Add new project

Launch the macOS app and click Add New in the Project section (upper right corner of the macOS app).

Add new project

Choose a project name (any label) and select the directory where you will save generated AppDeveloperKit.plist and AppDeveloperKit.swift files. This should be a directory in your project where other class files are kept for the iOS app target.

After choosing a directory, you will then be prompted to add the iOS app bundle id. Optionally add a description and then click Save.

Leave the Library checkbox unchecked. More information can be found in the section for Library Development.

Add generated files to project

Locate the files AppDeveloperKit.plist and AppDeveloperKit.swift in the directory chosen in previous step and add them to your iOS project.

Create a new class configuration for a Swift class that uses configurable properties.

Add new class

Click Add New in the Class Configuration section (middle right side of the macOS app).

Add new class

Choose a class name and an optional description and then click Save.

Other options

  • Publish changes
    • Leave this checked to publish property changes automatically to a live running app.
  • Enable
    • Leave this checked to automatically generate extension code for enabled properties to AppDeveloperKit.swift.
  • Library Component
  • Module fields (name, version)

Add a configurable property that will be instrumented in your iOS Swift class as described in the next section. This property will be saved in the AppDeveloperKit.plist file. Autogenerated extension code for this property will be saved in AppDeveloperKit.swift. This extension code will allow your app to retrieve plist values and communicate with the macOS app for live updates.

Add new property

Click Add New in the Property section (lower right corner of the macOS app).

Add new property

Choose a property name, type, value and an optional description and then click Save.

Leave the Enable checkbox checked to autogenerate configuration code to AppDeveloperKit.swift.

Instrument your classes with configurable properties that AppDeveloperKit can access.

Consider as an example a UISwitch that we wish to initialize from the configurable (computed) property "mybool".

@IBOutlet weak var boolSwitch: UISwitch!

1. Create a stored property as backing store. This must be the same name as the computed property, but with a leading underscore.

var _mybool: Bool = false

Notes:

  • This variable and the associated computed variable must not be marked as private, since the extension that needs to access these variables does not reside in the same source file (extension is in AppDeveloperKit.swift).
  • The default value is just a placeholder. The value will be overwritten by that obtained from AppDeveloperKit.plist (normal operation) or from macOS app (live updates).

2. Create the computed property.

var mybool: Bool {
get {
return _mybool
}
set {
_mybool = newValue
boolSwitch.isOn = _mybool
}
}

Notes:

  • The set is called during live updates while configuring the property with macOS app. It is not used during normal iOS app operation.
  • After setting the stored property you should update any affected app appearance. This might include:
    • Setting a UI control such as a switch or textfield.
    • Reloading a table.
    • Setting a color or font.
    • Calling setNeedsDisplay() to force a redraw.

In order to register your configurable class, you need to make an init call to the AppDeveloperKit framework. In order to properly cleanup when the class instance is released, you also need to make a deinit call.

adk_init

Where the class normally performs initialization call adk_init<className>(). In a viewcontroller this might be within viewDidLoad().

Follow with initialization of any UI, appearance, etc. that depends on configurable properties.

The following example shows how to initialize a UISwitch named boolSwitch, controlled by a configurable property named mybool, for a class named MainViewController

override func viewDidLoad() {
super.viewDidLoad()
adk_initMainViewController()
boolSwitch.isOn = _mybool
}
adk_deinit

In the class deinit call adk_deinit<className>()

deinit {
adk_deinitMainViewController()
}
Once you have completed the previous setup steps and have an instrumented iOS app, you can try some live property updates after establishing a connection:
  • Launch the macOS app
  • Launch the iOS app
  • Look for an active connection in the top left corner of the macOS app.
Mac App can communicate to iOS app client if:

1. Both are on same WiFi network.

Avoid using a guest network where devices may be unable to discover each other.

Switching to common WiFi connection: Terminate both iOS app and macOS app (if either was open) and relaunch.

2. Both are paired via Bluetooth. Turn on Bluetooth on Mac and iOS device.

On Mac: Click on Bluetooth icon and then Open BlueTooth Preferences. Make sure that the iOS device appears in the list of devices.

On iOS device: Go to Settings->Bluetooth. Make sure that Mac appears in list of either My Devices or Other Devices.

Begin pairing from iOS device. Does not appear to work if pairing is initiated from Mac. Select Mac from list. Dialog box will pop-up on Mac requesting permission to pair. Click Pair. Devices should show as paired on both iOS device and Mac.

Switching to Bluetooth connection: Terminate both iOS app and macOS app (if either was open) and relaunch.

3. Device running iOS app is physically connected to computer running Mac app. iOS app can be launched directly from device. The app does not need to be launched via Xcode. In this situation, it is not necessary for either Mac app or iOS app to have WiFi enabled.

Switching to physical connection: Terminate both iOS app and macOS app (if either was open) and relaunch.

Examples

Some demos to help you get started

In order to try the examples, first download AppDeveloperKit from GitHub. Click the "Clone or download" to get the link.

When working from Terminal you can navigate to a temporary directory and execute:

git clone https://github.com/AppDeveloperKit/AppDeveloperKit.git

Using Terminal, locate your download and navigate to AppDeveloperKit/ExampleApps/ADK_BasicExample

Execute: pod install

From Xcode open ADK_BasicExample.xcworkspace. Run the app on a device or simulator. It should appear as:

Basic example

Launch the macOS app and prepare a new project:

  • Create a new project and name it anything (i.e. "Basic Example")
  • Click on the Plist directory textfield and locate the directory containing AppDeveloperKit.plist. In our case this will be under the download directory at AppDeveloperKit/ExampleApps/ADK_BasicExample/ADK_BasicExample
  • Add the bundle identifier for this project which is com.scarter.ADK-BasicExample
  • Save

You should now have a connection to the running app. Try changing some of the properties in the MainViewController class configuration.

Using Terminal, locate your download and navigate to AppDeveloperKit/ExampleApps/ADK_LibraryExample

Execute: pod install

From Xcode open ADK_LibraryExample.xcworkspace. Run the app on a device or simulator. It should appear as:

Library example

Launch the macOS app and prepare a new project:

  • Create a new project and name it anything (i.e. "Library Example")
  • Click on the Plist directory textfield and locate the directory containing AppDeveloperKit.plist. In our case this will be under the download directory at AppDeveloperKit/ExampleApps/ADK_LibraryExample/ADK_LibraryExample
  • Add the bundle identifier for this project which is com.scarter.ADK-LibraryExample
  • Save

You should now have a connection to the running app. Try changing some of the properties in the BrickBaseViewController and BrickExample class configurations after you navigate to their corresponding screens in the app. You'll want to click on the Edit Properties button in the Class Config section to be able to edit the underlying JSON.

BrickBaseViewController vs. BrickExample
  • BrickBaseViewController
    • Class is taken directly from a Pod library: AppDeveloperKit-Library/Brick
    • This view controller class is instanced directly onto the storyboard, referenced from its Pod module as described in Using a Library.
    • The property values can be changed, but everything else is read only.
  • BrickExample
    • We subclass BrickBaseViewController as described in Subclassing
BrickKit

This demo uses BrickKit which was developed by Wayfair. It is a layout library for iOS and tvOS. You can learn more about BrickKit at https://github.com/wayfair/brickkit-ios

A more involved example can be found in this FlickrDemo.

This app requires a new download and an extra step to add an API key before running.

  • When working from Terminal you can navigate to a temporary directory and execute:
    • git clone https://github.com/scottcarter/FlickrDemo.git
  • Using Terminal, locate your download and navigate to FlickrDemo
    • Execute: pod install
  • From Xcode open FlickrDemo.xcworkspace
  • Run the app on a device or simulator. Tap on the Collection tab. It should appear as:
Flickr example

Launch the macOS app and prepare a new project:

  • Create a new project and name it anything (i.e. "Flickr Example")
  • Click on the Plist directory textfield and locate the directory containing AppDeveloperKit.plist.
  • Add the bundle identifier for this project which is com.scarter.FlickrDemo
  • Save

You should now have a connection to the running app. Try changing some of the properties in the various classes while on the corresponding screen.

Libraries

How to use, subclass and develop an AppDeveloperKit library

Configuring
If you have installed one or more AppDeveloperKit libraries with your Podfile, the Swift classes that are part of those libraries will be available for selection in the Class Configuration section as shown below. Note how the class name textfield has changed to a combo textfield/dropdown box.
Using a library

Assuming that you instance a library Swift class directly, any exposed configurable properties will become available for your use.

Notes
  • You will know you are using a library because the module name/version fields will be filled in and the Library Component checkbox will be checked.
  • You cannot add or remove any properties from a library component.
  • Only property values can be changed. Property name, type and description are read only fields.
  • Library component configuration is merged into your AppDeveloperKit.plist file on first save.
  • The library component will not show up in AppDeveloperKit.swift - the API code for these components is included with the Pod installation.
Using a View Controller Library component in a Storyboard

If the configurable library class is a view controller, you can instance it directly in your storyboard.

After dragging a new UIViewController to the storyboard, bring up the Identity Inspector. Select the Module that contains the library class and then the class name. Leave "Inherit Module From Target" unchecked.

Identity Inspector

If a library class supports subclassing, you have the opportunity to extend class functionality and add additional configurable properties as desired to your subclass.

Create configuration

There is a simple procedure for creating the configuration in the macOS app for a library subclass:

  1. Click Add New to start a new class configuration.
  2. Choose a library component that you wish to subclass from the class name dropdown.
  3. Save.
  4. Rename the class to the name of your subclass.
  5. Save.
Override adk_init() and adk_deinit()

A properly designed Library implements adk_init() and adk_deinit(). You have two options here:

  • Call your generated init and deinit methods where you override the Library methods.
  • Call your generated init and deinit methods elsewhere in your code (Ex: viewDidLoad() and deinit()). You would then override the Library methods and leave the bodies empty.

An example can be found in BrickExample.swift in the ADK_LibraryExample that is part of the ExampleApps directory in AppDeveloperKit.

This section will discuss how to develop an AppDeveloperKit library whose classes can be used as configurable components in an iOS project that uses the AppDeveloperKit iOS framework and macOS app.

It is highly recommended that you download and examine the AppDeveloperKit-Library example at https://github.com/AppDeveloperKit/AppDeveloperKit-Library as you review the process below.

Library development for AppDeveloperKit is an advanced topic. You should be comfortable with creating and publishing podspecs before attempting this.

Basic Approach

Each of these steps will be described in more detail

iOS project

A library cannot currently be delivered as an iOS framework, though we are thinking about Library Framework support. This process will describe how to deliver the library as a Cocoapod.

Add configurable library classes

These are the classes that will be delivered with your library.

Test classes

You should test your library before publishing. Test classes are meant to serve this purpose, but will not be delivered with your library. If you are creating library classes that can be subclassed (recommended), then you will likely have some test classes that are configurable. These test classes would subclass a library class (as the end user might) to ensure that there are no subclassing issues.

Other supporting infrastructure

Your library can deliver any functionality that you wish and does not need to be restricted to configurable classes. You might include non-configurable classes, storyboards, XIBs, image assets, etc.

New project - the Library checkbox

You must check the Library checkbox when creating a new project that will be used to deliver a library as a Pod. Here is what this will do:

  • New fields appear in the Project section for Module name and version. These must match exactly with your podpec name/version (see below).
  • The Library component button is enabled for new class configurations.
  • The class name field is restricted to a textfield (no dropdown). Libraries cannot use other libraries.
  • Individual plist, swift files (split files) are created for each library component class. More on this below.

Class configurations

Any configurable class that will be delivered in the library should have the Library component checkbox checked. Any test classes should not check this box.

Create and publish podspec

You will need to create and publish a podspec file. See the example at AppDeveloperKit/AppDeveloperKit-Library

Items to note:

  • The podspec name will become the module name for the library. It should match what you entered in the macOS project section. One exception is allowed: If you need to use a dash in the podspec name, replace it with an underscore in the macOS UI for module name. Why? Installation of your Pod (pod install) will make this substitution and the macOS UI must match the installed module name.
  • The podspec version will become the module version for the library. It should match what you entered in the macOS project section. Note that semantic versioning format is enforced in the macOS app, so please do the same in the podspec. Ex: 10.0.1 https://semver.org
  • Keep the Core subspec and reference it in subspecs that you create.
  • Create a subspec that will deliver your library. It should have a dependency on AppDeveloperKit-Library/Core and include your library assets
  • All subspecs delivering configurable classes need to include what is referred to here as the "split plist/swift" files or simply "split files" described in the next section.
Split files

When you use AppDeveloperKit in an iOS project, normal or library, the files AppDeveloperKit.plist and AppDeveloperKit.swift are created and you add them to your project. They go into sections Bundle Resources and Compile Sources respectively in Build Phases. These files should not be delivered with your Library.

When the Library checkbox is checked in the macOS app for Library development mode, additional files get generated and placed in a subdirectory called "AppDeveloperKit". This subdirectory is located where AppDeveloperKit.plist and AppDeveloperKit.swift get placed. These additional files are the Split files and do need to get included with the Library.

What are split files? You can think of them as slices of AppDeveloperKit.plist and AppDeveloperKit.swift, one slice for each class configuration that is marked as a Library component.

Split files follow the naming convention ADK_<class_name>.plist, ADK_<class_name>.swift. Assume we have a project named My-Library and we specified this directory in the Project section in the macOS app. Assume also that we have two configurable classes in our library that should be delivered named LibraryClass1 and LibraryClass2. The files being generated would include the following:

Do not include these in podspec
  • My-Library/AppDeveloperKit.plist
  • My-Library/AppDeveloperKit.swift
Include these in podspec
  • My-Library/AppDeveloperKit/ADK_LibraryClass1.swift
  • My-Library/AppDeveloperKit/ADK_LibraryClass1.plist
  • My-Library/AppDeveloperKit/ADK_LibraryClass2.swift
  • My-Library/AppDeveloperKit/ADK_LibraryClass2.plist
Split files in podspec

For the case above, your podspec might include:

s.name  = 'Configurable_Library'

s.subspec 'Core' do |core|
core.dependency 'AppDeveloperKit'
end

s.subspec 'Custom' do |custom|

# Add other resources as needed
custom.source_files = 'My-Library/LibraryClass*.swift', 'My-Library/AppDeveloperKit/*'
custom.dependency 'Configurable_Library/Core'

end

			
Designing a Library class for subclassing

To make your Library classes more flexible, design them so that they can be subclassed. What this basically means is using "open" instead of "public" for the following:

  • Configurable classes
  • Configurable stored and computed properties
  • Methods where you use the override keyword
  • The methods adk_init(), adk_deinit() - see below

Configurable classes that can be subclassed need to implement the methods adk_init(), adk_deinit(). These methods should be marked as open and simply call the generated init and deinit methods. The method adk_init() will then be called where you initialize and adk_deinit() will be called from deinit(). This structure allows the end user to override these methods when they subclass.

See the files BrickBaseViewController.swift and BrickExample.swift in AppDeveloperKit-Library for an example.

Test your library as an end user

Before you declare success, you should install your library as a Pod in a new project. Your testing should include all configurable classes. All classes that can be subclassed should also be tested for this usage.

To simplify your testing, you might consider re-using some or all of your test infrastructure from your library development project. An example of this can be found in AppDeveloperKit-Library (library development project) ADK_LibraryExample (the test of library).

Checklist

  • adk_init() and adk_deinit() methods implemented in configurable classes that can be subclassed.
  • The keyword "open" has been used where needed in configurable classes that can be subclassed.
  • Module name in podspec matches that in macOS app Project section.
  • Module version has been bumped in podspec and matches that in macOS app Project section.
  • Commits have been made after all changes in macOS app and in project. macOS app changes will affect split files.
  • Podspec has been published.
  • A sample app has been created that uses your library (as a Pod) and tests both direct instancing and subclassing of all configurable classes.

Known Issues

On our list to be fixed

Problem: Class configuration code for a Swift class is not auto-generated to AppDeveloperKit.swift unless at least one enabled property is added. Without the config code being generated, calls to adk_deinit<class_name>() and adk_init<class_name>() will not compile.

Workaround: This is only an issue if these method calls are added before any AppDeveloperKit properties have been instrumented in both iOS app and macOS UI. Comment out the method calls temporarily or instrument at least one AppDeveloperKit property.

Problem: If the class configuration Enable is unchecked, the methods adk_deinit<class_name>() and adk_init<class_name>() are not generated to AppDeveloperKit.swift and can cause compile errors.

Workaround: Leave this checkbox checked or comment out the affected methods temporarily if needed.

Problem: When a new project is added and a directory is selected that already has a pre-configured AppDeveloperKit.plist, the Bundle Id and Description fields are not populated.

Workaround: Add in the correct bundle id and Save. All the class and property configuration that was pre-configured is preserved and will show up in the UI.

Problem: Multiple instances of the same configurable class are not yet supported. You might encounter this issue for example in a configurable sub class of a UIView, where there is more than one instance of the view in it super view.

Workaround: Do not use AppDeveloperKit with a class whose instance will appear more than once.

Library mode is still under development. Currently an AppDeveloperKit Library can only be delivered via CocoaPods. We are thinking about how to support delivery via a Swift framework.

Library mode is still under development. There are several cases that are not yet handled well.

Plist version mismatch

The file AppDeveloperKit.plist (where configuration for all classes is stored) is versioned. An AppDeveloperKit library (delivered via Pod) also contains a version for the plist files that it contains. If the version matches, the macOS app will recognize and process the library (becomes available in class configuration name dropdown). If the version is not an exact match, the library is rejected.

  • The AppDeveloperKit macOS app should not reject libraries whose plist versions mismatch, but are still compatible.
  • The user should be notified when a Pod AppDeveloperKit library is encountered that is incompatible.

Module versioning

An AppDeveloperKit Pod library has a module version (set in podspec file). When a library class is selected and saved, the configuration information is merged from the library to the master AppDeveloperKit.plist for that project.

  • A library with a newer module version (than currently used) should alert the user and upgrade the configuration. Currently the module version is not used.

Missing library

When an AppDeveloperKit library is selected and used in a project class configuration, it is expected to always be present as a Pod.

  • The user should be notified if an AppDeveloperKit library is in use, but is not currently available as a Pod.

Troubleshooting

The AppDeveloperKit pod should install cleanly, but if you are having trouble you might consider updating your repo with:

pod repo update
pod update

Please also refer to the sample Podfile in the Setup section.

Getting a compile error when building iOS app? See if one of the following issues applies.

  • You added a property to macOS app that doesn't exist in iOS app. Add property to iOS class or disable property in macOS app temporarily.
  • Unresolved identifier 'adk_deinit* or 'adk_init*'. See below.

Use of unresolved identifier 'adk_deinit<class_name>' or 'adk_init<class_name>'

This error can occur if you have added these method calls to your Swift class, but have one of the following issues:

  • You have not added AppDeveloperKit.swift to your project. For all classes that you are instrumenting in your iOS code, save an enabled class configuration with enabled properties via macOS app. Add the generated AppDeveloperKit.swift to your project.
  • You have not yet saved at least one enabled property for that class in macOS app. See known issue for Class Config.
  • You have not enabled that class in Class Configuration section of macOS app.
Comment out these method calls until you have completed the macOS setup for that class.

Changes to properties in macOS app not visible in running iOS app? See if one of the following issues applies.

  • You aren't connected to iOS app. See section No connection
  • You changed the property type in macOS app. Will need to rebuild and restart iOS app.
  • You just added a new property. Rebuild and restart iOS app.
  • You changed the Swift Class Name field in Class Configuration.
  • The Enable checkbox is unchecked for that property. Auto-config code will not be generated
  • The Publish Changes checkbox is unchecked for that class configuration.

No connection

If there is an active connection from the macOS app to an iOS app, you will see a number greater than 0 in the macOS app in the field at the top labeled "Active connections to iOS apps"

No connection? See if one of the following issues applies.

  • iOS app is in the background
  • You initialized AppDeveloperKit with setup(enableLiveUpdates: false)
  • You don't have an active Wi-Fi connection for both the iOS app and macOS app
  • The iOS app and macOS app are not on the same Wi-Fi network
  • You are using a guest Wi-Fi network

Please review the section Establishing a connection

The following governs the use of all of AppDeveloperKit, including any interfaces (such as the macOS app) and other code (such as the iOS framework).

Copyright © 2017 Scott Carter. All rights reserved.                
                
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Credits

Our thanks for the use of the following software

Used in the AppDeveloperKit macOS app and/or iOS framework.

http://www.alpacajs.org

Copyright 2016 Gitana Software, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); 
you may not use this file except in compliance with the License. 

You may obtain a copy of the License at 
	http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
See the License for the specific language governing permissions and 
limitations under the License. 

For more information, please contact Gitana Software, Inc. at this
address:

  info@cloudcms.com

https://github.com/Microsoft/AppCenter-SDK-Apple

Visual Studio App Center SDK for Apple platforms

Copyright (c) Microsoft Corporation

All rights reserved.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

https://github.com/twbs/bootstrap

The MIT License (MIT)

Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

http://try.crashlytics.com/

Fabric: Copyright 2017 Google, Inc. All Rights Reserved. Use of this software 
is subject to the terms and conditions of the Fabric Software and Services 
Agreement located at https://fabric.io/terms. 
Crashlytics Kit: Copyright 2017 Crashlytics, Inc. All Rights Reserved. Use of 
this software is subject to the terms and conditions of the Crashlytics Terms 
of Service located at http://try.crashlytics.com/terms/terms-of-service.pdf and 
the Crashlytics Privacy Policy located at 
http://try.crashlytics.com/terms/privacy-policy.pdf. 
OSS: http://get.fabric.io/terms/opensource.txt
            

https://github.com/Anviking/Decodable

The MIT License (MIT)

Copyright (c) 2015 Johannes Lund

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
            

https://github.com/Cocoanetics/DTBonjour

Copyright (c) 2011, Oliver Drobnik All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer. 

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                

https://fabric.io

Copyright 2017 Google, Inc. All Rights Reserved. Use of this software is subject 
to the terms and conditions of the Fabric Software and Services Agreement located 
at https://fabric.io/terms.    OSS: http://get.fabric.io/terms/opensource.txt            
            

https://github.com/swisspol/GCDWebServer

Copyright (c) 2012-2014, Pierre-Olivier Latour
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * The name of Pierre-Olivier Latour may not be used to endorse
      or promote products derived from this software without specific
      prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           
            

https://handlebarsjs.com

Copyright (C) 2011-2017 by Yehuda Katz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

http://jquery.com

Projects referencing this document are released under the terms of the MIT license.

The MIT License is simple and easy to understand and it places almost no restrictions on what you can do with the Project.

You are free to use the Project in any other project (even commercial projects) as long as the copyright header is left intact.

https://github.com/realm/realm-cocoa

TABLE OF CONTENTS

1. Apache License version 2.0
2. Realm Components
3. Export Compliance

1. -------------------------------------------------------------------------------

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

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

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) 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.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

2. -------------------------------------------------------------------------------

REALM COMPONENTS

This software contains components with separate copyright and license terms.
Your use of these components is subject to the terms and conditions of the
following licenses.

For the Realm Platform Extensions component

  Realm Platform Extensions License

  Copyright (c) 2011-2017 Realm Inc All rights reserved

  Redistribution and use in binary form, with or without modification, is
  permitted provided that the following conditions are met:

  1. You agree not to attempt to decompile, disassemble, reverse engineer or
  otherwise discover the source code from which the binary code was derived.
  You may, however, access and obtain a separate license for most of the
  source code from which this Software was created, at
  http://realm.io/pricing/.

  2. Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from this
  software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.

3. -------------------------------------------------------------------------------

EXPORT COMPLIANCE

You understand that the Software may contain cryptographic functions that may be
subject to export restrictions, and you represent and warrant that you are not
(i) located in a jurisdiction that is subject to United States economic
sanctions (“Prohibited Jurisdiction”), including Cuba, Iran, North Korea,
Sudan, Syria or the Crimea region, (ii) a person listed on any U.S. government
blacklist (to include the List of Specially Designated Nationals and Blocked
Persons or the Consolidated Sanctions List administered by the U.S. Department
of the Treasury’s Office of Foreign Assets Control, or the Denied Persons List
or Entity List administered by the U.S. Department of Commerce)
(“Sanctioned Person”), or (iii) controlled or 50% or more owned by a Sanctioned
Person.

You agree to comply with all export, re-export and import restrictions and
regulations of the U.S. Department of Commerce or other agency or authority of
the United States or other applicable countries. You also agree not to transfer,
or authorize the transfer of, directly or indirectly, of the Software to any
Prohibited Jurisdiction, or otherwise in violation of any such restrictions or
regulations.           
            

https://github.com/ReactiveX/RxSwift

The MIT License Copyright © 2015 Krunoslav Zaher All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies of the Software, and to permit persons to whom the Software is furnished 
to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.          
            

https://github.com/bgrins/spectrum

Copyright (c) Brian Grinstead

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

https://github.com/malcommac/SwiftRichString

MIT License

Copyright (c) 2016 Daniele Margutti

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

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

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.