Skip to content

Commit

Permalink
refactor(dynamic_links)!: rework as part of #6979 (#7263)
Browse files Browse the repository at this point in the history
Co-authored-by: Elliot Hesp <elliot.hesp@gmail.com>
Co-authored-by: Salakar <mike.diarmid@gmail.com>
  • Loading branch information
3 people committed Dec 4, 2021
1 parent d213317 commit 4d51bff
Show file tree
Hide file tree
Showing 135 changed files with 4,589 additions and 2,617 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/firebase_dynamic_links.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ jobs:
- name: "Drive Example"
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 28
api-level: 29
arch: x86_64
# Firebase Database works without Google Play Services, so we don't use the `googleapis`
# emulator target as it's considerably slower on CI.
target: default
# Firebase Dynamic Links requires Google Play Services, so we use the `google_apis`
target: google_apis
profile: Nexus 5X
script: ./.github/workflows/scripts/drive-example.sh android

Expand Down
Binary file added docs/_assets/dl-apple-configure.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_assets/dl-apple-provision.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_assets/dl-apple-signing.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_assets/dl-apple-urlscheme.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_assets/dl-prefix.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/dynamic-links/android-integration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: Android Dynamic Links Setup
sidebar_label: Android Integration
description: Android requires additional configuration steps to be completed before you can receive dynamic links.
---

## Configure your App in the Firebase Console

Create a SHA-256 fingerprint using these [instructions](https://developers.google.com/android/guides/client-auth) for your app,
and add to your app in your Firebase console.

Next, go to the following location in your browser `[your-domain]/.well-known/assetlinks.json`. The response will have a target object
containing a "package_name" which ought to have your app's package name. Please do not proceed until you see this, it may take a while to register.

## AndroidManifest.xml Configuration

Add your deep link domains to your `android/app/src/main/AndroidManifest.xml` so your app can receive the Dynamic Link data after it is installed/updated
from the Play Store. Refer to the official docs to illustrate [setup](https://firebase.google.com/docs/dynamic-links/android/receive#add-an-intent-filter-for-deep-links).

For example:

```xml
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="example.com"
android:scheme="https"/>
</intent-filter>
```
66 changes: 66 additions & 0 deletions docs/dynamic-links/apple-integration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: iOS Dynamic Links Setup
sidebar_label: Apple Integration
description: iOS requires additional configuration steps to be completed before you can receive dynamic links.
---

## Apple Account

To setup Dynamic Links on iOS, it is a prerequisite that you have an Apple developer account [setup](https://developer.apple.com/programs/enroll/).

## Configure your App in the Firebase Console

Add an `App Store ID` & `Team ID` to your app in your Firebase console. If you do not have an `App Store ID` yet, you can put any number in here for now.
Your `Team ID` can be found in your Apple developer console.

<Image src="dl-apple-configure.jpg" alt="Apple Configuration" />

Test the domain (e.g. `https://your-dynamic-link-domain`) you have created in your Firebase console. Go to the following location in your browser `[your domain]/apple-app-site-association`.
The response will have a details array property containing an object that has the property `appID`. That will be your app's app ID (It may take some time for
your domain to register). Please ensure it is registered before proceeding.

## Apple Developer Console

Create a provisioning profile for your app. Please ensure you've enabled the `Associated Domain` capability which you should check before proceeding.

<Image src="dl-apple-provision.jpg" alt="Apple Provisioning Profile" />

## Signing & Capabilities

Open your app under the `TARGETS` header using XCode. Click the `Signing & Capabilities` tab. You will need to ensure your `Team` is registered, and your `Provisioning Profile` field is completed.
Please add the domain you created in your Firebase console to the `Associated Domains` and prefix with `applinks:`

<Image src="dl-apple-signing.jpg" alt="Signing & Capabilities" />

Click the `Info` tab, and add a `URL Type` to your project. The `Identifier` can be called `Bundle Id` or whatever you wish. Add your bundle identifier to the `URL Schemes` property.

<Image src="dl-apple-urlscheme.jpg" alt="URL Schemes" />

## Dynamic Links With Custom Domains

If you have set up a custom domain for your Firebase project, you must add the dynamic link URL prefix into your iOS project's `Info.plist` file by using the `FirebaseDynamicLinksCustomDomains` key.
You can add multiple URLs as well.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseDynamicLinksCustomDomains</key>
<array>
<string>https://custom.domain.io/path1</string>
<string>https://custom.domain.io/path2</string>
</array>

...other settings

</dict>
</plist>
```

If you don't add this, the dynamic link will invoke your app, but you cannot retrieve any deep link data you may need within your app, as the deep link will be completely ignored.

## Test Dynamic Links

To test your dynamic link, you will need to use a real device as it will not work on a simulator. You will also have to run the app in release mode (i.e. `flutter run --release`) as iOS will block you from opening
the app in debug mode from a dynamic link.
106 changes: 106 additions & 0 deletions docs/dynamic-links/overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: Dynamic Links for Firebase
sidebar_label: Overview
---

## What does it do?

Dynamic Links are links that work the way you want, on multiple platforms, and whether or not your app is already installed.
If a user opens a Dynamic Link on iOS or Android, they can be taken directly to the linked content in your native app.
If a user doesn't have your app installed, the user can be prompted to install it; then, after installation, your app starts
and can access the link.

<YouTube id="LvY1JMcrPF8"/>

## Installation

<Tabs
groupId="legacy-or-nullsafe"
defaultValue="legacy"
values={[
{ label: "Legacy", value: "legacy" },
{ label: "Null safety", value: "null-safe" },
]}
>
<TabItem value="legacy">
</TabItem>
<TabItem value="null-safe">

Ensure you're using the Flutter `stable` channel:

```bash
$ flutter channel stable
```

If your app is mixing legacy and null-safe packages, use the `--no-sound-null-safety` flag:
```bash
$ flutter run --no-sound-null-safety
```

For legacy package imports, place the following ignore comment to hide Dart analyzer warnings:

```dart
// ignore: import_of_legacy_library_into_null_safe
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
```
</TabItem>
</Tabs>

### 1. Add dependency

<Tabs
groupId="legacy-or-nullsafe"
defaultValue="legacy"
values={[
{ label: "Legacy", value: "legacy" },
{ label: "Null safety", value: "null-safe" },
]}
>
<TabItem value="legacy">

```yaml {5} title="pubspec.yaml"
dependencies:
flutter:
sdk: flutter
firebase_core: "^{{ plugins.firebase_core }}"
firebase_analytics: "^{{ plugins.firebase_dynamic_links }}"
```

</TabItem>
<TabItem value="null-safe">

```yaml {5} title="pubspec.yaml"
dependencies:
flutter:
sdk: flutter
firebase_core: "^{{ plugins.firebase_core }}"
firebase_dynamic_links: "^{{ plugins.firebase_dynamic_links_ns }}"
```

</TabItem>
</Tabs>

### 2. Download dependency

```
$ flutter pub get
```

### 4. Rebuild your app

Once complete, rebuild your Flutter application:

```bash
$ flutter run
```

## Platform Integration

Before using Dynamic Links, ensure you have configured your specific platform:

- [Android](./android-integration.mdx)
- [Apple](./apple-integration.mdx)

## Next steps

Once your platforms have been configured, head over to the [Usage](./usage.mdx) documentation.
152 changes: 151 additions & 1 deletion docs/dynamic-links/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,154 @@ title: Dynamic Links
sidebar_label: Usage
---

Dynamic Links usage
To start using the Dynamic Links package within your project, import it at the top of your project files:

```dart
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
```

Before using Dynamic Links, you must first have ensured you have [initialized FlutterFire](../overview.mdx#initializing-flutterfire).

To create a new Dynamic Links instance, call the [`instance`](!firebase_dynamic_links.FirebaseDynamicLinks.instance) getter on [`FirebaseDynamicLinks`](!firebase_dynamic_links.FirebaseDynamicLinks):

```dart
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
```

By default, this allows you to interact with Dynamic Links using the default Firebase App used whilst installing FlutterFire on your
platform.


On `Android`, if you'd like to use Dynamic Links with a secondary Firebase App, use the [`instanceFor`](!firebase_dynamic_links.FirebaseDynamicLinks.instanceFor) method:

```dart
// Android only
FirebaseApp secondaryApp = Firebase.app('SecondaryApp');
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instanceFor(app: secondaryApp);
```

## Setting up a prefix

Before using Dynamic Links, ensure you have first created a new link prefix on the
[Firebase Console](https://console.firebase.google.com/project/_/durablelinks).

For example, the `my-awesome-app.page.link` has been added on this project:

<Image src="dl-prefix.png" alt="Setting up a prefix" />

## Create a Dynamic Link

A dynamic link can be created directly from the Firebase Console, or programmatically via the `firebase_dynamic_links` plugin. Once a link has been created,
you can use send them to users (via emails, push notifications, in-app content etc.). Upon opening, your application can handle the link however you like, for
example opening a specific screen.

### Build Dynamic Link

To build a Dynamic Link, use the [`FirebaseDynamicLinks.buildLink`](!firebase_dynamic_links.buildLink) API in your application code like so:

```dart
final DynamicLinkParameters parameters = DynamicLinkParameters(
// The Dynamic Link URI domain. You can view created URIs on your Firebase console
uriPrefix: 'https://my-awesome-app.page.link',
// The deep Link passed to your application which you can use to affect change
link: Uri.parse('https://www.example.com/view-to-open'),
// Android application details needed for opening correct app on device/Play Store
androidParameters: const AndroidParameters(
packageName: androidPackageName,
minimumVersion: 1,
),
// iOS application details needed for opening correct app on device/App Store
iosParameters: const IOSParameters(
bundleId: iosBundleId,
minimumVersion: '2',
),
);
final Uri uri = await dynamicLinks.buildLink(parameters);
```

The method accepts a `DynamicLinkParameters` instance, which at a minimum requires a `uriPrefix` (defined in the Firebase Console),
along with a `link`, which is passed to your application when a user opens the app via a created link.

### Build Short Dynamic Link

You can also build a short Dynamic Link which simply makes the Dynamic Link URL shorter. This does entail an additional native SDK
request to the Firebase server whilst the above `buildLink()` does not. To build a short Dynamic Link, use the
[`FirebaseDynamicLinks.buildShortLink`](!firebase_dynamic_links.buildShortLink) API in your application code like so:

```dart
final DynamicLinkParameters parameters = DynamicLinkParameters(
// The Dynamic Link URI domain. You can view created URIs on your Firebase console
uriPrefix: 'https://example.page.link',
// The deep Link passed to your application which you can use to affect change
link: Uri.parse('https://www.example.com/view-to-open'),
// Android application details needed for opening correct app on device/Play Store
androidParameters: const AndroidParameters(
packageName: androidPackageName,
minimumVersion: 1,
),
// iOS application details needed for opening correct app on device/App Store
iosParameters: const IOSParameters(
bundleId: iosBundleId,
minimumVersion: '2',
),
);
final Uri uri = await FirebaseDynamicLinks.instance.buildShortLink(parameters);
```

## Handling Dynamic Links

To handle a Dynamic Link in your application, two scenarios require implementing.

### Background or Terminated

If the application is in the background or terminated, the [`FirebaseDynamicLinks.getInitialLink`](!firebase_dynamic_links.getInitialLink)
method allows you to retrieve the Dynamic Link that opened the application or brought it to the foreground.

This is an asynchronous request, so it makes sense to handle a link before rendering application logic, such as
a navigator. For example, you could handle this in the `main` function:

```dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseConfig.platformOptions);
// Get any initial links
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
runApp(MyApp(initialLink));
}
```

Within your application logic, you can then check whether a link was handled and perform an action, for example:

```dart
if (initialLink != null) {
final Uri deepLink = initialLink.link;
// Example of using the dynamic link to push the user to a different screen
Navigator.pushNamed(context, deepLink.path);
}
```

Alternatively, if you wish to identify if an exact Dynamic Link was used to open the application, pass it to
the `getDynamicLink` method instead:

```dart
String link = 'https://dynamic-link-domain/ke2Qa';
final PendingDynamicLinkData? initialLink = await FirebaseDynamicLinks.instance.getDynamicLink(Uri.parse(link));
```

## Listen for incoming links

Whilst the application is open, you may listen to Dynamic Links using a stream handler. The [`FirebaseDynamicLinks.onLink`](!firebase_dynamic_links.onLink)
getter returns a `Stream` containing a `PendingDynamicLinkData`:

```dart
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
Navigator.pushNamed(context, dynamicLinkData.link.path);
}).onError((error) {
// Handle errors
});
```
8 changes: 8 additions & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ module.exports = {
toReferenceAPI("firebase_crashlytics"),
toGithubExample("firebase_crashlytics"),
],
'Dynamic Links': [
"dynamic-links/overview",
"dynamic-links/android-integration",
"dynamic-links/apple-integration",
"dynamic-links/usage",
toReferenceAPI("firebase_dynamic_links"),
toGithubExample("firebase_dynamic_links"),
],
"Realtime Database": [
"database/overview",
toReferenceAPI("firebase_database"),
Expand Down

0 comments on commit 4d51bff

Please sign in to comment.