Skip to content

About

Offline CI checks for Android App Links and iOS Universal Links configuration

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

app-link-contract

Check that Android App Links and iOS Universal Links agree across your app configuration and website association files—before you publish them.

Android Studio and hosted validators help check files already served by a public domain. app-link-contract checks the local release inputs in one offline command: Android intent filters against assetlinks.json, and iOS associated-domain entitlements against Apple App Site Association (AASA) files. It also checks signing fingerprints and optional example URLs, so CI can catch configuration drift before device testing.

Try it

With Go 1.22 or later:

go run ./cmd/app-link-contract verify --config testdata/valid-config.json

The checked-in fixture passes and demonstrates both platforms. The app reads local files only; it does not make requests to the domains in the config.

Install the latest release with Go:

go install github.com/thisbejim/app-link-contract/cmd/app-link-contract@latest

Or download a macOS, Linux, or Windows archive from GitHub Releases.

Configure a project

Create app-links.json in your repository. Paths are relative to that file.

{
  "version": 1,
  "android": {
    "manifest": "android/app/src/main/AndroidManifest.xml",
    "application_id": "com.example.shop",
    "certificate_fingerprints": [
      "01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF:01:23:45:67:89:AB:CD:EF"
    ],
    "assetlinks": {
      "shop.example.com": "website/public/.well-known/assetlinks.json"
    }
  },
  "ios": {
    "entitlements": "ios/App/App.entitlements",
    "application_identifier": "ABCDE12345.com.example.shop",
    "aasa": {
      "shop.example.com": "website/public/.well-known/apple-app-site-association"
    }
  },
  "test_urls": [
    "https://shop.example.com/shop/123?campaign=summer"
  ]
}

Then run:

app-link-contract verify --config app-links.json

Replace the example fingerprint with the real app-signing fingerprint. If a build flavor changes hosts or application IDs, point manifest at that variant's merged release manifest instead of the source manifest shown above.

Use the SHA-256 fingerprint of the certificate that signs the app users install. With Play App Signing, that is the app-signing certificate shown in Play Console, not necessarily your upload or local build certificate. Add multiple fingerprints when the domain intentionally trusts more than one app signing certificate. Fingerprints can be upper- or lowercase and may include colons.

The iOS application_identifier is the app identifier prefix followed by the bundle identifier (for example, ABCDE12345.com.example.shop). It may differ from the Apple team ID. If the entitlements plist also contains application-identifier, the checker compares it with this value.

For an Android wildcard manifest host such as *.example.com, list an assetlinks.json mapping for each concrete host you serve and test. For an iOS wildcard entitlement applinks:*.example.com, map the root domain example.com to its AASA file, as Apple specifies.

Output

PASS app-link-contract: 0 error(s), 0 warning(s)
NOTE    ANDROID_ASSETLINKS_OK                android website/public/.well-known/assetlinks.json
        assetlinks for "shop.example.com" grants com.example.shop using a configured signing fingerprint
NOTE    IOS_AASA_OK                          ios website/public/.well-known/apple-app-site-association
        AASA file for "shop.example.com" lists ABCDE12345.com.example.shop
NOTE    ANDROID_TEST_URL_MATCHES             android android/app/build/intermediates/merged_manifest/...
        sample URL matches an HTTPS web intent filter
NOTE    IOS_TEST_URL_MATCHES                 ios website/public/.well-known/apple-app-site-association
        sample URL is admitted by this app's AASA rules

Diagnostics have stable codes. Errors return exit code 1; malformed arguments, config, or input files return 2. Warnings pass by default; use --strict to make them fail. CI tools can read JSON or SARIF:

app-link-contract verify --config app-links.json --format json
app-link-contract verify --config app-links.json --format sarif

Sample URL reports omit query strings and fragments. Their values are still used for AASA matching locally but are not copied into reports or CI logs.

What it checks

  • Android VIEW, DEFAULT, and BROWSABLE HTTPS intent filters, including android:autoVerify, host declarations, and common path matchers.
  • Each concrete Android host's local Digital Asset Links statement: app ID, delegate_permission/common.handle_all_urls, and configured SHA-256 signing certificate fingerprints.
  • iOS applinks: domains from XML entitlements, the configured app identifier, and each domain's local AASA app entry.
  • Sample URLs against Android path, pathPrefix, pathSuffix, and simple pathPattern filters, and against current AASA components or legacy paths rules.
  • Text, versioned JSON, and SARIF 2.1.0 output.

Limits

This is a local source/configuration check, not a device or server emulator. It cannot prove that a deployed file is reachable over HTTPS, redirects are absent, Apple or Android caches have refreshed, or the app's runtime router handles the URL. Verify the public endpoint and test on devices before release.

The Android input is an XML manifest; use a merged release manifest when build variants or manifest placeholders affect the final values. Android 15+ dynamic_app_link_components are reported as a boundary and are not applied to sample URL decisions. pathAdvancedPattern rules are reported as unverifiable. The iOS input is an XML entitlements plist; binary plists are not supported. Unknown AASA component keys do not produce a claimed URL match.

Development

go test ./...
go test -race ./...
go vet ./...
go build ./...

The runtime has no third-party dependencies. See product specification and opportunity research. Licensed under MIT; see LICENSE.

About

Offline CI checks for Android App Links and iOS Universal Links configuration

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages