diff --git a/.github/workflows/firebase_dynamic_links.yaml b/.github/workflows/firebase_dynamic_links.yaml
new file mode 100644
index 000000000000..003911e13a09
--- /dev/null
+++ b/.github/workflows/firebase_dynamic_links.yaml
@@ -0,0 +1,68 @@
+name: firebase_dynamic_links
+
+on:
+ pull_request:
+ paths:
+ - "packages/firebase_dynamic_links/**"
+ - ".github/workflows/firebase_dynamic_links.yaml"
+ push:
+ branches:
+ - master
+ paths-ignore:
+ - "docs/**"
+ - "**.md"
+
+env:
+ FLUTTERFIRE_PLUGIN_SCOPE: "*firebase_dynamic_links*"
+ FLUTTERFIRE_PLUGIN_SCOPE_EXAMPLE: "*firebase_dynamic_links_example*"
+ # TODO(Salakar): `flutter_driver` does not yet support NNBD
+ FLUTTER_COMMAND_FLAGS: "--no-sound-null-safety"
+
+jobs:
+ android:
+ if: github.event_name == 'pull_request'
+ runs-on: macos-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ fetch-depth: 0
+ - name: "Install Flutter"
+ run: ./.github/workflows/scripts/install-flutter.sh stable
+ - name: "Install Tools"
+ run: ./.github/workflows/scripts/install-tools.sh
+ - name: "Build Example"
+ run: ./.github/workflows/scripts/build-example.sh android
+ - name: "Drive Example"
+ uses: reactivecircus/android-emulator-runner@v2
+ with:
+ api-level: 28
+ 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
+ profile: Nexus 5X
+ script: ./.github/workflows/scripts/drive-example.sh android
+
+ apple:
+ runs-on: macos-latest
+ timeout-minutes: 35
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ fetch-depth: 0
+ - name: "Install Flutter"
+ run: ./.github/workflows/scripts/install-flutter.sh stable
+ - name: "Install Tools"
+ run: |
+ ./.github/workflows/scripts/install-tools.sh
+ flutter config --enable-macos-desktop
+ - name: "Build iOS Example"
+ run: ./.github/workflows/scripts/build-example.sh ios
+ - name: "Drive iOS Example"
+ run: ./.github/workflows/scripts/drive-example.sh ios
+# TODO: Currently does not have macOS support.
+# - name: "Build MacOS Example"
+# run: ./.github/workflows/scripts/build-example.sh macos
+# - name: "Drive MacOS Example"
+# run: ./.github/workflows/scripts/drive-example.sh macos
diff --git a/packages/firebase_dynamic_links/example/android/app/build.gradle b/packages/firebase_dynamic_links/example/android/app/build.gradle
index ffbba7441917..61748d009e2c 100644
--- a/packages/firebase_dynamic_links/example/android/app/build.gradle
+++ b/packages/firebase_dynamic_links/example/android/app/build.gradle
@@ -1,60 +1,52 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader('UTF-8') { reader ->
- localProperties.load(reader)
- }
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
- throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
- flutterVersionCode = '1'
+ flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
- flutterVersionName = '1.0'
+ flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
+apply plugin: 'com.google.gms.google-services'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 29
-
- lintOptions {
- disable 'InvalidPackage'
- }
-
- defaultConfig {
- applicationId "io.flutter.plugins.firebasedynamiclinksexample"
- minSdkVersion 16
- targetSdkVersion 28
- versionCode flutterVersionCode.toInteger()
- versionName flutterVersionName
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- buildTypes {
- release {
- signingConfig signingConfigs.debug
- }
+ compileSdkVersion 29
+
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+
+ defaultConfig {
+ applicationId "io.flutter.plugins.firebasedynamiclinksexample"
+ minSdkVersion 16
+ targetSdkVersion 29
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ signingConfig signingConfigs.debug
}
+ }
}
flutter {
- source '../..'
-}
-
-dependencies {
- androidTestImplementation 'androidx.test:runner:1.2.0'
- androidTestImplementation 'androidx.test:rules:1.2.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ source '../..'
}
-
-apply plugin: 'com.google.gms.google-services'
diff --git a/packages/firebase_dynamic_links/example/android/app/src/main/AndroidManifest.xml b/packages/firebase_dynamic_links/example/android/app/src/main/AndroidManifest.xml
index e156bd08f6fc..a53f556e5e51 100644
--- a/packages/firebase_dynamic_links/example/android/app/src/main/AndroidManifest.xml
+++ b/packages/firebase_dynamic_links/example/android/app/src/main/AndroidManifest.xml
@@ -1,21 +1,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
+ package="io.flutter.plugins.firebasedynamiclinksexample">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/EmbeddingV1Activity.java b/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/EmbeddingV1Activity.java
deleted file mode 100644
index bc1f40e5b98a..000000000000
--- a/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/EmbeddingV1Activity.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.flutter.plugins.firebasedynamiclinksexample;
-
-import android.os.Bundle;
-import dev.flutter.plugins.e2e.E2EPlugin;
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin;
-import io.flutter.plugins.firebasedynamiclinks.FirebaseDynamicLinksPlugin;
-
-public class EmbeddingV1Activity extends FlutterActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- FlutterFirebaseCorePlugin.registerWith(
- registrarFor("io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin"));
- // TODO(Salakar) rename as part of re-work FirebaseDynamicLinksPlugin -> FlutterFirebaseDynamicLinksPlugin
- FirebaseDynamicLinksPlugin.registerWith(
- registrarFor("io.flutter.plugins.firebasedynamiclinks.FirebaseDynamicLinksPlugin"));
- E2EPlugin.registerWith(registrarFor("dev.flutter.plugins.e2e.E2EPlugin"));
- }
-}
diff --git a/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/MainActivity.java b/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/MainActivity.java
new file mode 100644
index 000000000000..e2dac8d0905e
--- /dev/null
+++ b/packages/firebase_dynamic_links/example/android/app/src/main/java/io/flutter/plugins/firebasedynamiclinksexample/MainActivity.java
@@ -0,0 +1,5 @@
+package io.flutter.plugins.firebasedynamiclinksexample;
+
+import io.flutter.embedding.android.FlutterActivity;
+
+public class MainActivity extends FlutterActivity {}
diff --git a/packages/firebase_dynamic_links/example/android/app/src/main/res/values/styles.xml b/packages/firebase_dynamic_links/example/android/app/src/main/res/values/styles.xml
index 00fa4417cfbe..11beaaf68414 100644
--- a/packages/firebase_dynamic_links/example/android/app/src/main/res/values/styles.xml
+++ b/packages/firebase_dynamic_links/example/android/app/src/main/res/values/styles.xml
@@ -1,8 +1,17 @@
-
+
+
+
+
diff --git a/packages/firebase_dynamic_links/example/android/settings.gradle b/packages/firebase_dynamic_links/example/android/settings.gradle
index 5a2f14fb18f6..44e62bcf06ae 100644
--- a/packages/firebase_dynamic_links/example/android/settings.gradle
+++ b/packages/firebase_dynamic_links/example/android/settings.gradle
@@ -1,15 +1,11 @@
include ':app'
-def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
+def properties = new Properties()
-def plugins = new Properties()
-def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
-if (pluginsFile.exists()) {
- pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
-}
+assert localPropertiesFile.exists()
+localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
-plugins.each { name, path ->
- def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
- include ":$name"
- project(":$name").projectDir = pluginDirectory
-}
+def flutterSdkPath = properties.getProperty("flutter.sdk")
+assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/packages/firebase_dynamic_links/example/pubspec.yaml b/packages/firebase_dynamic_links/example/pubspec.yaml
index cec44cbeff92..fcce1b116517 100644
--- a/packages/firebase_dynamic_links/example/pubspec.yaml
+++ b/packages/firebase_dynamic_links/example/pubspec.yaml
@@ -23,7 +23,11 @@ dependency_overrides:
path: ../../firebase_core/firebase_core_web
dev_dependencies:
- pedantic: ^1.11.0
+ drive: 0.1.0
+ flutter_driver:
+ sdk: flutter
+ flutter_test:
+ sdk: flutter
flutter:
uses-material-design: true
diff --git a/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e.dart b/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e.dart
new file mode 100644
index 000000000000..41f72515d0db
--- /dev/null
+++ b/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e.dart
@@ -0,0 +1,72 @@
+// @dart = 2.9
+// Copyright 2020, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:drive/drive.dart' as drive;
+import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void testsMain() {
+ group('DynamicLinks', () {
+ test('buildUrl', () async {
+ const String androidPackageName =
+ 'io.flutter.plugins.firebasedynamiclinksexample';
+ const String iosBundleId =
+ 'com.google.FirebaseCppDynamicLinksTestApp.dev';
+ const String urlHost = 'cx4k7.app.goo.gl';
+ const String link = 'https://dynamic.link.example/helloworld';
+
+ final DynamicLinkParameters parameters = DynamicLinkParameters(
+ uriPrefix: 'https://$urlHost',
+ link: Uri.parse(link),
+ androidParameters: AndroidParameters(
+ packageName: androidPackageName,
+ minimumVersion: 1,
+ ),
+ dynamicLinkParametersOptions: DynamicLinkParametersOptions(
+ shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
+ ),
+ iosParameters: IosParameters(
+ bundleId: iosBundleId,
+ minimumVersion: '2',
+ ),
+ );
+
+ final Uri uri = await parameters.buildUrl();
+
+ // androidParameters.minimumVersion
+ expect(
+ uri.queryParameters['amv'],
+ '1',
+ );
+ // iosParameters.minimumVersion
+ expect(
+ uri.queryParameters['imv'],
+ '2',
+ );
+ // androidParameters.packageName
+ expect(
+ uri.queryParameters['apn'],
+ androidPackageName,
+ );
+ // iosParameters.bundleId
+ expect(
+ uri.queryParameters['ibi'],
+ iosBundleId,
+ );
+ // link
+ expect(
+ uri.queryParameters['link'],
+ Uri.encodeFull(link),
+ );
+ // uriPrefix
+ expect(
+ uri.host,
+ urlHost,
+ );
+ });
+ });
+}
+
+void main() => drive.main(testsMain);
diff --git a/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e_test.dart b/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e_test.dart
new file mode 100644
index 000000000000..84950df392c9
--- /dev/null
+++ b/packages/firebase_dynamic_links/example/test_driver/firebase_dynamic_links_e2e_test.dart
@@ -0,0 +1,8 @@
+// @dart = 2.9
+// Copyright 2020, the Chromium project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:drive/drive_driver.dart' as drive;
+
+void main() => drive.main();
diff --git a/packages/firebase_dynamic_links/ios/Classes/FLTFirebaseDynamicLinksPlugin.m b/packages/firebase_dynamic_links/ios/Classes/FLTFirebaseDynamicLinksPlugin.m
index 8ee4a9d681f1..f3b89bfa6d04 100644
--- a/packages/firebase_dynamic_links/ios/Classes/FLTFirebaseDynamicLinksPlugin.m
+++ b/packages/firebase_dynamic_links/ios/Classes/FLTFirebaseDynamicLinksPlugin.m
@@ -138,20 +138,18 @@ - (void)onDeepLinkResult:(FIRDynamicLink *_Nullable)dynamicLink error:(NSError *
}
}
-- (BOOL)checkForDynamicLink:(NSURL *)url {
+- (void)checkForDynamicLink:(NSURL *)url {
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
[self onDeepLinkResult:dynamicLink error:nil];
- return YES;
}
- return NO;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary *)options {
[self checkForDynamicLink:url];
- // results of this are ORed and NO doesn't affect other delegate interceptors' result
+ // Results of this are ORed and NO doesn't affect other delegate interceptors' result.
return NO;
}
@@ -160,49 +158,48 @@ - (BOOL)application:(UIApplication *)application
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
[self checkForDynamicLink:url];
- // results of this are ORed and NO doesn't affect other delegate interceptors' result
+ // Results of this are ORed and NO doesn't affect other delegate interceptors' result.
return NO;
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
- restorationHandler:
-#if defined(__IPHONE_12_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0)
- (nonnull void (^)(NSArray> *_Nullable))restorationHandler {
-#else
- (nonnull void (^)(NSArray *_Nullable))restorationHandler {
-#endif // __IPHONE_12_0
+ restorationHandler:(nonnull void (^)(NSArray *_Nullable))restorationHandler {
__block BOOL retried = NO;
+ void (^completionBlock)(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error);
+ void (^__block __weak weakCompletionBlock)(FIRDynamicLink *_Nullable dynamicLink,
+ NSError *_Nullable error);
+ weakCompletionBlock = completionBlock = ^(FIRDynamicLink *_Nullable dynamicLink,
+ NSError *_Nullable error) {
+ if (!error && dynamicLink && dynamicLink.url) {
+ [self onDeepLinkResult:dynamicLink error:nil];
+ }
- id completion =
- ^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
- if (!error && dynamicLink && dynamicLink.url) {
- [self onDeepLinkResult:dynamicLink error:nil];
- }
- }
- // Per Apple Tech Support, a network failure could occur when returning from background on
- // iOS 12. https://github.com/AFNetworking/AFNetworking/issues/4279#issuecomment-447108981 So
- // we'll retry the request once
- if (error && !retried && [NSPOSIXErrorDomain isEqualToString:error.domain] &&
- error.code == 53) {
- retried = YES;
- [[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
- completion:completion];
- }
- // We could send this to Dart and maybe have a onDynamicLinkError stream but there's also
- // a good chance the `userActivity.webpageURL` might not be for a Firebase dynamic link,
- // which needs consideration - so we'll log this for now, logging will get picked up by
- // Crashlytics automatically if its integrated.
- if (error)
- NSLog(@"FLTFirebaseDynamicLinks: Unknown error occurred when attempting to handle a universal "
+ // Per Apple Tech Support, a network failure could occur when returning from background on
+ // iOS 12. https://github.com/AFNetworking/AFNetworking/issues/4279#issuecomment-447108981 So
+ // we'll retry the request once
+ if (error && !retried && [NSPOSIXErrorDomain isEqualToString:error.domain] &&
+ error.code == 53) {
+ retried = YES;
+ [[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
+ completion:weakCompletionBlock];
+ }
+ // We could send this to Dart and maybe have a onDynamicLinkError stream but there's also
+ // a good chance the `userActivity.webpageURL` might not be for a Firebase dynamic link,
+ // which needs consideration - so we'll log this for now, logging will get picked up by
+ // Crashlytics automatically if its integrated.
+ if (error)
+ NSLog(
+ @"FLTFirebaseDynamicLinks: Unknown error occurred when attempting to handle a universal "
@"link: %@",
error);
-};
+ };
-[[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL completion:completion];
+ [[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
+ completion:completionBlock];
-// results of this are ORed and NO doesn't affect other delegate interceptors' result
-return NO;
+ // Results of this are ORed and NO doesn't affect other delegate interceptors' result.
+ return NO;
}
- (FIRDynamicLinkShortenerCompletion)createShortLinkCompletion:(FlutterResult)result {
diff --git a/packages/firebase_dynamic_links/pubspec.yaml b/packages/firebase_dynamic_links/pubspec.yaml
index 156e642f194f..a889d0f272a8 100644
--- a/packages/firebase_dynamic_links/pubspec.yaml
+++ b/packages/firebase_dynamic_links/pubspec.yaml
@@ -17,7 +17,6 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
- pedantic: ^1.11.0
url_launcher: ^6.0.2
flutter:
diff --git a/packages/firebase_dynamic_links/test/firebase_dynamic_links_e2e.dart b/packages/firebase_dynamic_links/test/firebase_dynamic_links_e2e.dart
deleted file mode 100644
index 393bf35c078b..000000000000
--- a/packages/firebase_dynamic_links/test/firebase_dynamic_links_e2e.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
- testWidgets('buildUrl', (WidgetTester tester) async {
- final DynamicLinkParameters parameters = DynamicLinkParameters(
- uriPrefix: 'https://cx4k7.app.goo.gl',
- link: Uri.parse('https://dynamic.link.example/helloworld'),
- androidParameters: AndroidParameters(
- packageName: 'io.flutter.plugins.firebasedynamiclinksexample',
- minimumVersion: 0,
- ),
- dynamicLinkParametersOptions: DynamicLinkParametersOptions(
- shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
- ),
- iosParameters: IosParameters(
- bundleId: 'com.google.FirebaseCppDynamicLinksTestApp.dev',
- minimumVersion: '0',
- ),
- );
-
- final Uri uri = await parameters.buildUrl();
- expect(
- uri.toString(),
- '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',
- );
- });
-}