A one day, single-track online event celebrating the future of cross-platform app development

DocsプラグインCLI

ユニバーサルリンクとアプリリンクによるディープリンク

プラットフォーム: iOS, Android

ユニバーサルリンク(iOS)とアプリリンク(Android)は、ユーザーをネイティブアプリ内の特定のコンテンツに直接誘導する機能を提供します(一般的にはディープリンクとして知られています)。

ユーザーがディープリンクをタップまたはクリックすると、デバイスの Web ブラウザや Web サイトを経由せずに、ユーザーは直接アプリに移動します。アプリがインストールされていない場合は、ユーザーはウェブサイトに誘導されます。ユーザーが Web サイトに直接移動した場合、ユーザーは Web サイトに留まります。このように、ディープリンクは、ウェブ、iOS、Android 向けに構築されたクロスプラットフォームのアプリにとって、優れた機能となっています。

メリット

  • 安全。ユニバーサル/アプリリンクでは、HTTPS URL を使用してお客様が所有するウェブサイトのドメインにリンクするため、他のアプリがお客様のリンクを使用できないことが保証されます。
  • シームレスな体験。1 つの URL がウェブサイトとアプリの両方で機能するため、ユーザーはエラーなく目的のコンテンツに正常にアクセスできます。
  • エンゲージメントの向上。リンクは、メールクライアントや検索エンジンの検索結果などから開くことができます。

デモビデオ

ここでは、実際にどのように見えるかを説明します。この例では、ユーザーはネイティブアプリをインストールしています。メールに記載されたアプリのリンクをタップすると、アプリ自体に直接アクセスできます。まず、ルートリンクをタップすると(https://beerswift.app)、アプリのメインページに移動します。次に、ディープリンクをタップすると(https://beerswift.app/tabs/tab3)、Tab3のページが表示されます。

前提条件

  • 設定済みの Capacitor app があること。
  • iOS の場合、Apple Developer Program に登録していること。

例示のため、ウェブアプリのリンクとして https://beerswift.app を使用します。

Capacitor App API によるディープリンクルーティング

ディープリンクがクリックされた後にネイティブアプリが開かれた場合、モバイル OS は自動的にユーザーをどこに誘導すればよいかを知りません。これは、アプリの起動時に Capacitor App API を使用して、アプリ自体に実装する必要があります。

Web サイトとアプリのパスが一致しない場合は、より高度な URL パターンマッチングを実装する必要があります(例は 本ガイド を参照)。モバイルアプリとウェブアプリが同じコードベースを使用している場合は、同じ URL にリダイレクトするだけなので、非常に簡単です。以下の例はこれを前提としています。

Angular

Routing should be implemented in app.component.ts. Start by importing NgZone and Router from Angular, then App from Capacitor:

import { Component, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { Plugins } from '@capacitor/core';
const { App } = Plugins;

Next, add Router and NgZone to the constructor:

constructor(private router: Router, private zone: NgZone) {
    this.initializeApp();
}

Last, listen for the appUrlOpen event, and redirect when a deep link is found:

initializeApp() {
    App.addListener('appUrlOpen', (data: any) => {
        this.zone.run(() => {
            // Example url: https://beerswift.app/tabs/tab2
            // slug = /tabs/tab2
            const slug = data.url.split(".app").pop();
            if (slug) {
                this.router.navigateByUrl(slug);
            }
            // If no match, do nothing - let regular routing
            // logic take over
        });
    });
}

React

There’s a variety of options for React. One approach is to wrap the App API listener functionality in a new component, then add it inside of App.tsx. Start by creating AppUrlListener.tsx then import the React Router useHistory hook as well as the Capacitor App API:

import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Plugins } from '@capacitor/core';
const { App: CapApp } = Plugins;

Next, define the AppUrlListener component, listening for the appUrlOpen event then redirecting when a deep link is found:

const AppUrlListener: React.FC<any> = () => {
  let history = useHistory();
  useEffect(() => {
    CapApp.addListener('appUrlOpen', (data: any) => {
      // Example url: https://beerswift.app/tabs/tab2
      // slug = /tabs/tab2
      const slug = data.url.split('.app').pop();
      if (slug) {
        history.push(slug);
      }
      // If no match, do nothing - let regular routing
      // logic take over
    });
  }, []);

  return null;
};

export default AppUrlListener;

Over in App.tsx, import the new component:

import AppUrlListener from './pages/AppUrlListener';

Then add it inside of IonReactRouter (or wherever your app is bootstrapped, just ensure that the History hook is available):

const App: React.FC = () => {
  return (
    <IonApp>
      <IonReactRouter>
        <AppUrlListener></AppUrlListener>
        <IonRouterOutlet>
          <Route path="/home" component={Home} exact={true} />
          <Route exact path="/" render={() => <Redirect to="/home" />} />
        </IonRouterOutlet>
      </IonReactRouter>
    </IonApp>
  );
};

Vue

VueJS offers a first party routing system that integrates natively with Vue called Vue Router. To set up deep linking with Vue Router, start in the file that you used to configure all of your routes (usually routes.js or something similar).

First we import the capacitor App from plugins along with Vue and VueRouter.

import { Plugins } from '@capacitor/core';
const { App } = Plugins;
import Vue from 'vue';
import VueRouter from 'vue-router';

Next, configure your routes using the Vue Router (more information on Getting Started with Vue Router).

const router = new VueRouter({
  routes: [],
});

It’s recommended to use mode: history so you don’t have to deal with the #.

Let Vue know that you are using Vue Router and register the router within Vue:

const VueApp = new Vue({
  router,
}).$mount('#app');

Finally, we need to register our app for deep linking. To do that, we add an event listener to the appUrlOpen event on the Capacitor App. Capacitor will pick this up, then we hand it off to Vue Router to navigate to the page requested.

App.addListener('appUrlOpen', function (data) {
  // Example url: https://beerswift.app/tabs/tabs2
  // slug = /tabs/tabs2
  const slug = data.url.split('.app').pop();

  // We only push to the route if there is a slug present
  if (slug) {
    router.push({
      path: slug,
    });
  }
});

Creating Site Association Files

In order for Apple and Google to permit deep links to open your app, a two-way association between your website and app must be created. One file for each must be created and placed within a .well-known folder on your website, like so: https://beerswift.app/.well-known/.

Continue on for iOS and Android configuration details.

iOS Configuration

iOS configuration involves creating a site association file and configuring the native app to recognize the app domain.

You must be enrolled in the Apple Developer Program.

Create Site Association File

First, log into the Apple Developer site. Navigate to the “Certificates, Identifiers, & Profiles” section and select your app’s identifier. Note the Team ID and Bundle ID, and under Capabilities, toggle “Associated Domains” then save:

iOS Identifier Config

Next, create the site association file (apple-app-site-association).

Note: Despite being a JSON file, do not save it with a file extension.

An example of the apple-app-site-association file is below. Be sure to replace TEAMID.BUNDLEID with your own IDs (example: 8L65AZE66A.com.netkosoft.beerswift).

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAMID.BUNDLEID",
        "paths": ["*"]
      }
    ]
  }
}

Next, upload the file to your web site (hosted on HTTPS), then validate that it’s configured correctly using Apple’s tool here. The URL should follow this format: https://beerswift.app/.well-known/apple-app-site-association

Add Associated Domain

The final step is to configure the iOS app to recognize incoming links. Open Xcode, then navigate to Signing & Capabilities. Click “+ Capability”, then choose Associated Domains. In the Domains entry that appears, edit it using the format applinks:yourdomain.com:

Xcode Associated Domain

Android Configuration

Android configuration involves creating a site association file and configuring the native app to recognize app links using an intent filter.

Create Site Association File

The Site Association file requires the SHA256 fingerprint of your Android certificate.

If you don’t have one, create a certificate:

keytool -genkey -v -keystore KEY-NAME.keystore -alias ALIAS -keyalg RSA -keysize 2048 -validity 10000

Using your existing (or newly created) Keystore certificate, use the keytool command to list the keystore’s details:

keytool -list -v -keystore my-release-key.keystore

The printed output will include the SHA256 fingerprint:

Keytool output

Next, use Google’s Asset Links tool to create the Site Association file. Fill in the website domain, app package name, and SHA256 fingerprint, then click “Generate statement”:

Android Identifier Config

Copy the JSON output into a new local file under .well-known/assetlinks.json.

// assetlinks.json
[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.netkosoft.beerswift",
      "sha256_cert_fingerprints": ["43:12:D4:27:D7:C4:14..."]
    }
  }
]

Deploy the file to your website (hosted on HTTPS), then verify it by clicking the “Test statement” button in the Asset Link tool. If it’s configured correctly, a Success message will appear:

Success! Host [website] grants app deep linking to [app package].

Add Intent Filter

The final step is to configure the Android app to recognize incoming links. To do so, add a new Intent Filter to AndroidManifest.xml within the <activity> element:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="beerswift.app" />
</intent-filter>

The complete Activity should look similar to this:

<activity
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
    android:name="com.netkosoft.beerswift.MainActivity"
    android:label="@string/title_activity_main"
    android:theme="@style/AppTheme.NoActionBarLaunch"
    android:launchMode="singleTask">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https" android:host="beerswift.app" />
    </intent-filter>
</activity>

Details: Website Configuration

Website configuration will vary based on the tools and backend used. A few suggestions are below.

Angular

Place the association files under src/.well-known. Next, configure the build process to deploy these files exactly as-is (ensuring that Apple/Google can read them correctly). Open angular.json and under architect => assets, add a new entry to the array:

{
  "glob": "**/*",
  "input": "src/.well-known",
  "output": ".well-known/"
}

Build then deploy the site.

NuxtJS

Place the association files under static/.well-known. No additional steps are necessary; simply build then deploy the site.

React

Place the association files under public/.well-known. No additional steps are necessary; simply build then deploy the site.

WordPress

See here for WordPress instructions.

Verification

To verify that the websites and the native apps are configured correctly, the website needs to host the Site Association files but the apps do not need to be in the app stores.

Connect a device to your computer, build and deploy the native apps, then test by tapping on website links. If the native app opens, all steps have been implemented correctly.

Resources

Previous
<- CI/CD
Next
デプロイとアップデート ->
Contribute ->