Skip to content

Commit 8bf9b22

Browse files
[firebase_dynamic_links] support v2 embedding (#1372)
1 parent 14ef4ea commit 8bf9b22

File tree

14 files changed

+215
-33
lines changed

14 files changed

+215
-33
lines changed

packages/firebase_dynamic_links/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.5.0+8
2+
3+
* Support v2 embedding. This will remain compatible with the original embedding and won't require app migration.
4+
15
## 0.5.0+7
26

37
* Add `getDynamicLink` to support expanding from short links.

packages/firebase_dynamic_links/android/build.gradle

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,33 @@ android {
3434
dependencies {
3535
api 'com.google.firebase:firebase-dynamic-links:16.1.8'
3636
implementation 'com.google.firebase:firebase-common:16.1.0'
37-
implementation 'androidx.annotation:annotation:1.0.0'
3837
}
3938
}
4039

4140
apply from: file("./user-agent.gradle")
41+
42+
// TODO(bparrishMines): Remove this hack once androidx.lifecycle is included on stable. https://github.com/flutter/flutter/issues/42348
43+
afterEvaluate {
44+
def containsEmbeddingDependencies = false
45+
for (def configuration : configurations.all) {
46+
for (def dependency : configuration.dependencies) {
47+
if (dependency.group == 'io.flutter' &&
48+
dependency.name.startsWith('flutter_embedding') &&
49+
dependency.isTransitive())
50+
{
51+
containsEmbeddingDependencies = true
52+
break
53+
}
54+
}
55+
}
56+
if (!containsEmbeddingDependencies) {
57+
android {
58+
dependencies {
59+
def lifecycle_version = "1.1.1"
60+
compileOnly "android.arch.lifecycle:runtime:$lifecycle_version"
61+
compileOnly "android.arch.lifecycle:common:$lifecycle_version"
62+
compileOnly "android.arch.lifecycle:common-java8:$lifecycle_version"
63+
}
64+
}
65+
}
66+
}

packages/firebase_dynamic_links/android/gradle.properties

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/firebase_dynamic_links/android/src/main/java/io/flutter/plugins/firebasedynamiclinks/FirebaseDynamicLinksPlugin.java

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
package io.flutter.plugins.firebasedynamiclinks;
66

7+
import android.app.Activity;
78
import android.content.Intent;
89
import android.net.Uri;
9-
import androidx.annotation.NonNull;
1010
import com.google.android.gms.tasks.OnCompleteListener;
1111
import com.google.android.gms.tasks.OnFailureListener;
1212
import com.google.android.gms.tasks.OnSuccessListener;
@@ -15,6 +15,10 @@
1515
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks;
1616
import com.google.firebase.dynamiclinks.PendingDynamicLinkData;
1717
import com.google.firebase.dynamiclinks.ShortDynamicLink;
18+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
19+
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
20+
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
21+
import io.flutter.plugin.common.BinaryMessenger;
1822
import io.flutter.plugin.common.MethodCall;
1923
import io.flutter.plugin.common.MethodChannel;
2024
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
@@ -26,16 +30,50 @@
2630
import java.util.List;
2731
import java.util.Map;
2832

29-
/** FirebaseDynamicLinksPlugin */
30-
public class FirebaseDynamicLinksPlugin implements MethodCallHandler, NewIntentListener {
31-
private final Registrar registrar;
32-
private final MethodChannel channel;
33-
34-
private FirebaseDynamicLinksPlugin(Registrar registrar, MethodChannel channel) {
35-
this.registrar = registrar;
33+
/**
34+
* Flutter plugin accessing for Firebase Dynamic Links API.
35+
*
36+
* <p>Instantiate this in an add to app scenario to gracefully handle activity and context changes.
37+
*/
38+
public class FirebaseDynamicLinksPlugin
39+
implements FlutterPlugin, ActivityAware, MethodCallHandler, NewIntentListener {
40+
private Activity activity;
41+
private MethodChannel channel;
42+
43+
private FirebaseDynamicLinksPlugin(Activity activity, MethodChannel channel) {
44+
this.activity = activity;
3645
this.channel = channel;
3746
}
3847

48+
/**
49+
* Default Constructor.
50+
*
51+
* <p>Use this when adding the plugin to your FlutterEngine
52+
*/
53+
public FirebaseDynamicLinksPlugin() {}
54+
55+
/**
56+
* Registers a plugin with the v1 embedding api {@code io.flutter.plugin.common}.
57+
*
58+
* <p>Calling this will register the plugin with the passed registrar. However, plugins
59+
* initialized this way won't react to changes in activity or context.
60+
*
61+
* @param registrar attaches this plugin's {@link
62+
* io.flutter.plugin.common.MethodChannel.MethodCallHandler} to the registrar's {@link
63+
* io.flutter.plugin.common.BinaryMessenger}.
64+
*/
65+
public static void registerWith(Registrar registrar) {
66+
final MethodChannel channel = createChannel(registrar.messenger());
67+
final FirebaseDynamicLinksPlugin plugin =
68+
new FirebaseDynamicLinksPlugin(registrar.activity(), channel);
69+
registrar.addNewIntentListener(plugin);
70+
channel.setMethodCallHandler(plugin);
71+
}
72+
73+
private static MethodChannel createChannel(final BinaryMessenger messenger) {
74+
return new MethodChannel(messenger, "plugins.flutter.io/firebase_dynamic_links");
75+
}
76+
3977
@Override
4078
public boolean onNewIntent(Intent intent) {
4179
FirebaseDynamicLinks.getInstance()
@@ -54,7 +92,7 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
5492
.addOnFailureListener(
5593
new OnFailureListener() {
5694
@Override
57-
public void onFailure(@NonNull Exception e) {
95+
public void onFailure(Exception e) {
5896
Map<String, Object> exception = new HashMap<>();
5997
exception.put("code", e.getClass().getSimpleName());
6098
exception.put("message", e.getMessage());
@@ -66,12 +104,37 @@ public void onFailure(@NonNull Exception e) {
66104
return false;
67105
}
68106

69-
public static void registerWith(Registrar registrar) {
70-
final MethodChannel channel =
71-
new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_dynamic_links");
72-
final FirebaseDynamicLinksPlugin plugin = new FirebaseDynamicLinksPlugin(registrar, channel);
73-
registrar.addNewIntentListener(plugin);
74-
channel.setMethodCallHandler(plugin);
107+
@Override
108+
public void onAttachedToEngine(FlutterPluginBinding binding) {
109+
channel = createChannel(binding.getFlutterEngine().getDartExecutor());
110+
channel.setMethodCallHandler(this);
111+
}
112+
113+
@Override
114+
public void onDetachedFromEngine(FlutterPluginBinding binding) {
115+
channel.setMethodCallHandler(null);
116+
}
117+
118+
@Override
119+
public void onAttachedToActivity(ActivityPluginBinding binding) {
120+
activity = binding.getActivity();
121+
binding.addOnNewIntentListener(this);
122+
}
123+
124+
@Override
125+
public void onDetachedFromActivityForConfigChanges() {
126+
activity = null;
127+
}
128+
129+
@Override
130+
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
131+
activity = binding.getActivity();
132+
binding.addOnNewIntentListener(this);
133+
}
134+
135+
@Override
136+
public void onDetachedFromActivity() {
137+
activity = null;
75138
}
76139

77140
@Override
@@ -134,7 +197,7 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
134197
.addOnFailureListener(
135198
new OnFailureListener() {
136199
@Override
137-
public void onFailure(@NonNull Exception e) {
200+
public void onFailure(Exception e) {
138201
result.error(e.getClass().getSimpleName(), e.getMessage(), null);
139202
}
140203
});
@@ -146,20 +209,19 @@ private void handleGetDynamicLink(final Result result, Uri uri) {
146209

147210
private void handleGetInitialDynamicLink(final Result result) {
148211
// If there's no activity, then there's no initial dynamic link.
149-
if (registrar.activity() == null) {
212+
if (activity == null) {
150213
result.success(null);
151214
return;
152215
}
153216

154217
addDynamicLinkListener(
155-
FirebaseDynamicLinks.getInstance().getDynamicLink(registrar.activity().getIntent()),
156-
result);
218+
FirebaseDynamicLinks.getInstance().getDynamicLink(activity.getIntent()), result);
157219
}
158220

159221
private OnCompleteListener<ShortDynamicLink> createShortLinkListener(final Result result) {
160222
return new OnCompleteListener<ShortDynamicLink>() {
161223
@Override
162-
public void onComplete(@NonNull Task<ShortDynamicLink> task) {
224+
public void onComplete(Task<ShortDynamicLink> task) {
163225
if (task.isSuccessful()) {
164226
Map<String, Object> url = new HashMap<>();
165227
url.put("url", task.getResult().getShortLink().toString());

packages/firebase_dynamic_links/example/android/app/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ flutter {
5252
}
5353

5454
dependencies {
55+
androidTestImplementation 'androidx.test:runner:1.2.0'
56+
androidTestImplementation 'androidx.test:rules:1.2.0'
57+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
5558
}
5659

5760
apply plugin: 'com.google.gms.google-services'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.flutter.plugins.firebasedynamiclinks;
2+
3+
import androidx.test.rule.ActivityTestRule;
4+
import dev.flutter.plugins.e2e.FlutterRunner;
5+
import io.flutter.plugins.firebasedynamiclinksexample.EmbeddingV1Activity;
6+
import org.junit.Rule;
7+
import org.junit.runner.RunWith;
8+
9+
@RunWith(FlutterRunner.class)
10+
public class EmbeddingV1ActivityTest {
11+
@Rule
12+
public ActivityTestRule<EmbeddingV1Activity> rule =
13+
new ActivityTestRule<>(EmbeddingV1Activity.class);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.flutter.plugins.firebasedynamiclinks;
2+
3+
import androidx.test.rule.ActivityTestRule;
4+
import dev.flutter.plugins.e2e.FlutterRunner;
5+
import io.flutter.plugins.firebasedynamiclinksexample.MainActivity;
6+
import org.junit.Rule;
7+
import org.junit.runner.RunWith;
8+
9+
@RunWith(FlutterRunner.class)
10+
public class MainActivityTest {
11+
@Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(MainActivity.class);
12+
}

packages/firebase_dynamic_links/example/android/app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@
1414
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
1515
android:hardwareAccelerated="true"
1616
android:windowSoftInputMode="adjustResize">
17-
<meta-data
18-
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
19-
android:value="true" />
2017
<intent-filter>
2118
<action android:name="android.intent.action.MAIN"/>
2219
<category android:name="android.intent.category.LAUNCHER"/>
2320
</intent-filter>
2421
</activity>
22+
<activity
23+
android:name=".EmbeddingV1Activity"
24+
android:theme="@style/LaunchTheme"
25+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale"
26+
android:hardwareAccelerated="true"
27+
android:windowSoftInputMode="adjustResize">
28+
</activity>
2529
</application>
2630
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.flutter.plugins.firebasedynamiclinksexample;
2+
3+
import android.os.Bundle;
4+
import io.flutter.app.FlutterActivity;
5+
import io.flutter.plugins.GeneratedPluginRegistrant;
6+
7+
public class EmbeddingV1Activity extends FlutterActivity {
8+
@Override
9+
protected void onCreate(Bundle savedInstanceState) {
10+
super.onCreate(savedInstanceState);
11+
GeneratedPluginRegistrant.registerWith(this);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package io.flutter.plugins.firebasedynamiclinksexample;
22

3-
import android.os.Bundle;
4-
import io.flutter.app.FlutterActivity;
5-
import io.flutter.plugins.GeneratedPluginRegistrant;
3+
import dev.flutter.plugins.e2e.E2EPlugin;
4+
import io.flutter.embedding.android.FlutterActivity;
5+
import io.flutter.embedding.engine.FlutterEngine;
6+
import io.flutter.plugins.firebasedynamiclinks.FirebaseDynamicLinksPlugin;
7+
import io.flutter.plugins.urllauncher.UrlLauncherPlugin;
68

79
public class MainActivity extends FlutterActivity {
10+
// TODO(bparrishMines): Remove this once v2 of GeneratedPluginRegistrant rolls to stable. https://github.com/flutter/flutter/issues/42694
811
@Override
9-
protected void onCreate(Bundle savedInstanceState) {
10-
super.onCreate(savedInstanceState);
11-
GeneratedPluginRegistrant.registerWith(this);
12+
public void configureFlutterEngine(FlutterEngine flutterEngine) {
13+
flutterEngine.getPlugins().add(new FirebaseDynamicLinksPlugin());
14+
flutterEngine.getPlugins().add(new E2EPlugin());
15+
flutterEngine.getPlugins().add(new UrlLauncherPlugin());
1216
}
1317
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
org.gradle.jvmargs=-Xmx1536M
22
android.enableR8=true
3+
android.useAndroidX=true
4+
android.enableJetifier=true

packages/firebase_dynamic_links/example/pubspec.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ dependencies:
1111

1212
url_launcher: ^5.1.6
1313

14+
dev_dependencies:
15+
e2e: ^0.2.1
16+
flutter_driver:
17+
sdk: flutter
18+
1419
flutter:
1520
uses-material-design: true

packages/firebase_dynamic_links/pubspec.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: firebase_dynamic_links
22
description: Flutter plugin for Google Dynamic Links for Firebase, an app solution for creating
33
and handling links across multiple platforms.
4-
version: 0.5.0+7
4+
version: 0.5.0+8
55

66
author: Flutter Team <[email protected]>
77
homepage: https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_dynamic_links
@@ -11,6 +11,9 @@ dependencies:
1111
sdk: flutter
1212

1313
dev_dependencies:
14+
e2e: ^0.2.1
15+
flutter_driver:
16+
sdk: flutter
1417
flutter_test:
1518
sdk: flutter
1619
url_launcher: ^4.2.0
@@ -24,4 +27,4 @@ flutter:
2427

2528
environment:
2629
sdk: ">=2.0.0-dev.28.0 <3.0.0"
27-
flutter: ">=1.5.0 <2.0.0"
30+
flutter: ">=1.9.1+hotfix.4 <2.0.0"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:flutter_test/flutter_test.dart';
2+
import 'package:e2e/e2e.dart';
3+
4+
import '../lib/firebase_dynamic_links.dart';
5+
6+
void main() {
7+
E2EWidgetsFlutterBinding.ensureInitialized();
8+
9+
testWidgets('buildUrl', (WidgetTester tester) async {
10+
final DynamicLinkParameters parameters = DynamicLinkParameters(
11+
uriPrefix: 'https://cx4k7.app.goo.gl',
12+
link: Uri.parse('https://dynamic.link.example/helloworld'),
13+
androidParameters: AndroidParameters(
14+
packageName: 'io.flutter.plugins.firebasedynamiclinksexample',
15+
minimumVersion: 0,
16+
),
17+
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
18+
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
19+
),
20+
iosParameters: IosParameters(
21+
bundleId: 'com.google.FirebaseCppDynamicLinksTestApp.dev',
22+
minimumVersion: '0',
23+
),
24+
);
25+
26+
final Uri uri = await parameters.buildUrl();
27+
expect(
28+
uri.toString(),
29+
'https://cx4k7.app.goo.gl?amv=0&apn=io.flutter.plugins.firebasedynamiclinksexample&ibi=com.google.FirebaseCppDynamicLinksTestApp.dev&imv=0&link=https%3A%2F%2Fdynamic.link.example%2Fhelloworld',
30+
);
31+
});
32+
}

0 commit comments

Comments
 (0)