All Projects → timonus → Openermanifest

timonus / Openermanifest

Licence: apache-2.0
Set of rules powering Opener for iOS

Labels

Projects that are alternatives of or similar to Openermanifest

Srsly
🦉 Modern high-performance serialization utilities for Python (JSON, MessagePack, Pickle)
Stars: ✭ 189 (-3.08%)
Mutual labels:  json
Json Schema Spec
The JSON Schema I-D sources
Stars: ✭ 2,441 (+1151.79%)
Mutual labels:  json
Sdk
Library for using Grafana' structures in Go programs and client for Grafana REST API.
Stars: ✭ 193 (-1.03%)
Mutual labels:  json
Json5
UTF-8 compatible JSON5 parser for PHP
Stars: ✭ 189 (-3.08%)
Mutual labels:  json
Mtgjson
MTGJSON build scripts for Magic: the Gathering
Stars: ✭ 191 (-2.05%)
Mutual labels:  json
Bridge.
Minecraft Add-on Editor | We strive to provide the best development experience possible
Stars: ✭ 193 (-1.03%)
Mutual labels:  json
Know Your Http Well
HTTP headers, media-types, methods, relations and status codes, all summarized and linking to their specification.
Stars: ✭ 2,205 (+1030.77%)
Mutual labels:  json
Cti Python Stix2
OASIS TC Open Repository: Python APIs for STIX 2
Stars: ✭ 194 (-0.51%)
Mutual labels:  json
Jsonapi Utils
Build JSON API-compliant APIs on Rails with no (or less) learning curve.
Stars: ✭ 191 (-2.05%)
Mutual labels:  json
Mxisd
Federated Matrix Identity Server
Stars: ✭ 194 (-0.51%)
Mutual labels:  json
Flexirest
Flexirest - The really flexible REST API client for Ruby
Stars: ✭ 188 (-3.59%)
Mutual labels:  json
Hjson
Hjson, a user interface for JSON
Stars: ✭ 2,330 (+1094.87%)
Mutual labels:  json
Tq
Perform a lookup by CSS selector on an HTML input
Stars: ✭ 193 (-1.03%)
Mutual labels:  json
Rapidyaml
Rapid YAML - a library to parse and emit YAML, and do it fast.
Stars: ✭ 183 (-6.15%)
Mutual labels:  json
Swagger Toolbox
💡 Swagger schema model (in yaml, json) generator from json data
Stars: ✭ 194 (-0.51%)
Mutual labels:  json
Wretch
A tiny wrapper built around fetch with an intuitive syntax. 🍬
Stars: ✭ 2,285 (+1071.79%)
Mutual labels:  json
Csmodel
CSModel is a concise and efficient model framework for iOS/OSX, and provides nested Model to compare values and copy values.
Stars: ✭ 192 (-1.54%)
Mutual labels:  json
Jsonframe Cheerio
simple multi-level scraper json input/output for Cheerio
Stars: ✭ 196 (+0.51%)
Mutual labels:  json
Validation
validation api extracted from play
Stars: ✭ 194 (-0.51%)
Mutual labels:  json
Jl
jl — JSON Logs, a development tool for working with structured JSON logging.
Stars: ✭ 194 (-0.51%)
Mutual labels:  json

Opener Manifest

Opener is an app for iOS that allows people to open web links in native apps instead. It does so by transforming web links within an engine powered by a rule set. This repo is the public version of that rule set.

Overview

There are four main entities (apps, actions, formats, and browsers) under three top level keys (apps, actions, and browsers) that define a many-to-many relationship between web URLs and the apps they can be opened in.

Actions contain formats as child dictionaries, and formats are matched with apps through identifiers. Browsers contain keys from each of the action, app, and format constructs and are intended to be capable of handling any http or https URL as an input.

Apps

The apps top level key in the manifest contains an ordered list of dictionaries, each representing an app supported by Opener. Each app contains the following fields

Key Type Description
identifier string A human-readable identifier for this app, used elsewhere in the manifest.
name string The user-facing name for this app within Opener.
storeId number as string The identifier of the app on the App Store. (Optional in v2, required in v1)
iconURL URL string A URL to an icon for this app, mutually exclusive with storeId. This is intended for first party app support.
scheme URL string A URL containing only the scheme that will open this app.
new bool Indicates whether or not this app will be include in the "New Apps" group in Opener.
platform string Specifies if this app should only show up on iPhone/iPod Touch (value=phone) or on iPad (value=pad), shows on both if unspecified. (Opener 1.0.1 and above)
country string If the app isn't globally available, including a country code in which it is available in this field will allow the app's icon to show regardless of the user's store. (Opener 1.1.1 and above)

For example, if Opener were to include itself as an app

{
    "identifier": "opener",
    "storeId": "989565871",
    "name": "Opener",
    "scheme": "opener://",
    "new": true
}

Actions

The actions top level key in the manifest contains a list of dictionaries, each corresponding to a web URL-to-native URL rule. There's a many-to-many relationship between the values in actions and apps.

Common values

Key Type Description
title string The user-facing title for this action.
regex string A regular expression string that the input URL is matched against. If this regex is matched by Opener for a given input, this action will appear in the list of available opening options.
headers bool Indicates if headers should be included in the string that regex is matched with. If true, the headers are included in the input as a JSON encoded string separated from the input URL by a newline. (Opener 1.0.2 and above)
formats array of dictionaries Specifies the apps that an action can be opened in (see below).

Formats

Because an action could taken in multiple apps, there's an array within each action dictionary named formats. Each entry in this array matches the input URL with an app-specific output for the given action. Each of these contains the following keys.

Key Type Description
appId string The identifier of the app that this action applies to. Should match the identifier of an app.
format string The regex template applied to the input. Mutually exclusive with script.

Advanced URL generation in formats

Some app native URLs can't be generated using simple regex templating, they require lookups or encoding of some sort. To do this, action formats can provide JavaScript methods that are executed to convert input URLs to app native action URLs.

Key Type Description
script JavaScript string Mutually exclusive with format, can coexist with script2.
script2 JavaScript string Mutually exclusive with format, can coexist with script.

This script must contain a JavaScript function named process that takes two inputs, a URL and an anonymous function to be called upon completion. Once complete, the completion handler should be called passing the result or null on failure.

For example

function process(url, completionHandler) {
    // do something with URL...
    url = rot13(url);
    
    completionHandler(url);
}

The contents of the script field are executed in a UIWebView, which gives it a full set of functionality but is a bit slow and costly. The script2 field is instead run inside of an engine that uses JavaScriptCore, which is much more performant but doesn't have some small functionality that the UIWebView has. For convenience, the environment that the script2 field is executed in has the following functions.

  • httpRequest makes a blocking call to download the contents of a URL.
  • jsonRequest makes a blocking call to download the contents of a URL and parses the results into JSON.
  • btoa base 64 encodes its input.
  • htmlDecode decodes HTML entities in the input string.
  • base64DigitsToBase10String takes an array of base 64 digits as integers and converts them into a base 10 string. (Used for decoding some types of identifiers).

If script2 is provided it's used, otherwise we fall back to script if specified. Clients prior to version 1.1.8 are only capable of using the script field.

Some common scenarios and best practices for using the script fields are outlined here. Opener enforces a timeout of 15 seconds if completionHandler isn't called.

Testing

To keep Opener maintainable, tests for actions can and should be provided.

At the action level:

Key Type Description
testInputs array of strings An array of test inputs that will be run against regex then each action.

At the format level:

Key Type Description
testResults array of strings or nulls An array of expected results for this format for each of the test inputs. null should be used to specify that a test input should not match

For example

{
    ...
    "regex": "http(?:s)?://(?:www\\.)?foo\.bar/(\\d+).*$",
    "testInputs": [
        "https://foo.bar/1234"
        "http://www.foo.bar/wat"
    ],
    "formats": [
        {
            ...
            "format": "foo-app://entry/$1",
            "testResults": [
                "foo-app://entry/1234",
                null
            ]
        },
        {
            ...
            "script": "function process(url, completion) { completion('bar-app://' + encodeURIComponent(url)); }",
            "testResults": [
                "bar-app://https%3A%2F%2Ffoo.bar%2F1234",
                null
            ]
        }
    ]
}

Testing formats that have headers is not currently possible.

Browsers

Support for opening any http or https URL in browsers was added in Opener 1.1. Browsers live under the browsers top level key, each one contains a subset of the keys from the other app, action, and format dictionaries.

Key Type Description
identifier string A human-readable identifier for this app, used elsewhere in the manifest.
name string The user-facing name for this app within Opener.
storeId number as string The identifier of the app on the App Store. (Optional in v2, required in v1)
iconURL URL string A URL to an icon for this app, mutually exclusive with storeId. This is intended for first party app support.
scheme URL string A URL containing only the scheme that will open this app.
new bool Indicates whether or not this app will be include in the "New Apps" group in Opener.
platform string Specifies if this app should only show up on iPhone/iPod Touch (value=phone) or on iPad (value=pad), shows on both if unspecified. (Opener 1.0.1 and above)
country string If the app isn't globally available, including a country code in which it is available in this field will allow the app's icon to show regardless of the user's store. (Opener 1.1.1 and above)
regex string A regular expression string that the input URL is matched against, used for pattern replacements.
format string The regex template applied to the input. Mutually exclusive with script.
script JavaScript string Mutually exclusive with format.
testInputs array of strings An array of test inputs that will be run against regex then each action.
testResults array of strings or nulls An array of expected results for this format for each of the test inputs. null should be used to specify that a test input should not match

For example, here's Google Chrome's dictionary:

{
    "name": "Chrome",
    "identifier": "chrome",
    "scheme": "googlechrome://",
    "storeId": "535886823",
    "regex": "http(s)?(.*)$",
    "format": "googlechrome$1$2",
    "testInputs": [
        "http://www.opener.link/",
        "https://twitter.com/openerapp"
    ],
    "testResults": [
        "googlechrome://www.opener.link/",
        "googlechromes://twitter.com/openerapp"
    ]
}

Redirect Rules

There's a fourth top-level key in the manifest named redirects that's not directly tied to opening in particular apps. If Opener's unable to resolve a URL into a set of actions it performs a HTTP HEAD request to follow its input URL to its final destination, then retries resolving on that URL. For example, a bit.ly link to a Tweet wouldn't naturally resolve because Opener has no way of knowing the bit.ly link points to a Tweet, so we perform a HEAD request to get the final URL, which does resolve.

Some popular services have URL redirection that doesn't work when followed through an HTTP HEAD request, but instead require loading HTML to get a redirect to occur. Links of this variety break Opener's system for resolving URLs, and loading up an invisible web page just to see if something redirects doesn't seem acceptable. Some of these services include

  • Google (and some Google AMP links)
  • Facebook (and Facebook Messenger)
  • Reddit
  • Tumblr
  • Pinterest

redirects solves this by serving as a static set of rules for mapping input URLs to what they'd redirect to if they were loaded up as HTML from services like this. The format for these rules is pretty simple.

Key Type Description
Dictionary key string The keys for the entries in redirects are regular expressions to match. If a match is found, the rule within it used.
param string A URL query parameter name. If the rule is matched, the value for param is used as the resulting URL to redirect to. Mutually exclusive with format.
format string A regex template to be used on the input if the rule is matched. Mutually exclusive with param

So, for example if links like https://mycoolsite.com/redirect?redirecturl=foobar.com redirect to foobar.com, you'd use a rule like this.

"https://mycoolsite\\.com/redirect.*$" {
	"param": "redirecturl"
}

redirects also supports lightweight tests in the form of a dictionary under the tests key. The keys of tests are sample inputs, and the values are the expected outputs.

"https://mycoolsite\\.com/redirect.*$" {
	"param": "redirecturl",
	"test": {
		"https://mycoolsite.com/redirect?redirecturl=foobar.com": "foobar.com"
	}
}

redirects are only supported by Opener version 1.5.8 and above.

Minify Script

There's a python script included named minify.py, this script takes a copy of the manifest as an input and outputs a file with suffix -minified.json as output. This script strips out all unnecessary keys for Opener's operation when running in the client (testing, documentation, etc.) and minifies the JSON to be compact.

Sample usage:

python minify.py openerManifest-v3.json

Versions

The manifest file has a -v3 on the end, this indicates the major version of the manifest. If there are ever changes to the app that make the manifest not backwards compatible with a former version, the suffix of the manifest file is bumped.

Manifest Version App Version Changes
v2 1.0.10 Made app dictionary storeId field optional. This was required in v1. Change was made in order to support first party apps, which lack an iTunes identifier.
v3 1.1.8 Add support for script2 field, which is processed using JavaScriptCore instead of a UIWebView.
v4 1.8.10 Shrink numerous fields (`displayName`=`name`, `storeIdentifier`=`storeId`, `appIdentifier`=`appId`, `includeHeaders`=`headers`, `redirectRules`=`redirects`) and removed trailing `:`s from `scheme` field such that all keys and many more values fit in [tagged pointers to occupy less memory](https://www.mikeash.com/pyblog/friday-qa-2015-07-31-tagged-pointer-strings.html).

Contributing

Pull requests are welcome! Because Opener is a closed source app with an experience that I'd like to keep great, I'm going to be pedantic about these requests. I will likely manipulate the order of the apps and actions that are added, and handle the new flag for them.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].