Skip to content

Commit 2daa95d

Browse files
authored
Replace uni_links package with built-in deep link support (#206)
1 parent 28664ce commit 2daa95d

File tree

12 files changed

+58
-149
lines changed

12 files changed

+58
-149
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ upload the apps to GCS (automatically deleted after 30 days).
2323
- Push notification via [firebase_messaging](https://pub.dev/packages/firebase_messaging)
2424
- Dark mode: on / off / auto
2525
- Developer hidden menu (tap "Version" thrice)
26+
- Android, iOS domain association with [built-in deep link support](https://docs.flutter.dev/ui/navigation/deep-linking)
2627

2728
## FAQ
2829

android/app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
2323
android:exported="true"
2424
android:hardwareAccelerated="true"
25-
android:launchMode="singleTop"
25+
android:launchMode="singleInstance"
2626
android:theme="@style/LaunchTheme"
2727
android:windowSoftInputMode="adjustResize">
2828
<!-- Specifies an Android theme to apply to this Activity as soon as
@@ -33,6 +33,11 @@
3333
android:name="io.flutter.embedding.android.NormalTheme"
3434
android:resource="@style/NormalTheme" />
3535

36+
<!-- https://docs.flutter.dev/cookbook/navigation/set-up-app-links -->
37+
<meta-data
38+
android:name="flutter_deeplinking_enabled"
39+
android:value="true" />
40+
3641
<intent-filter>
3742
<action android:name="android.intent.action.MAIN" />
3843
<category android:name="android.intent.category.LAUNCHER" />

ios/Podfile.lock

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ PODS:
140140
- sqflite (0.0.3):
141141
- Flutter
142142
- FMDB (>= 2.7.5)
143-
- uni_links (0.0.1):
144-
- Flutter
145143
- url_launcher_ios (0.0.1):
146144
- Flutter
147145
- video_player_avfoundation (0.0.1):
@@ -168,7 +166,6 @@ DEPENDENCIES:
168166
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
169167
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
170168
- sqflite (from `.symlinks/plugins/sqflite/ios`)
171-
- uni_links (from `.symlinks/plugins/uni_links/ios`)
172169
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
173170
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
174171
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
@@ -232,8 +229,6 @@ EXTERNAL SOURCES:
232229
:path: ".symlinks/plugins/sign_in_with_apple/ios"
233230
sqflite:
234231
:path: ".symlinks/plugins/sqflite/ios"
235-
uni_links:
236-
:path: ".symlinks/plugins/uni_links/ios"
237232
url_launcher_ios:
238233
:path: ".symlinks/plugins/url_launcher_ios/ios"
239234
video_player_avfoundation:
@@ -282,7 +277,6 @@ SPEC CHECKSUMS:
282277
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
283278
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
284279
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
285-
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
286280
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
287281
video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126
288282
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47

ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
<string>bee1edd35d32695d76209b09c46c60dc</string>
4848
<key>FacebookDisplayName</key>
4949
<string>com.daohoangson.flutter_ttdemo</string>
50+
<key>FlutterDeepLinkingEnabled</key>
51+
<true/>
5052
<key>ITSAppUsesNonExemptEncryption</key>
5153
<false/>
5254
<key>LSApplicationQueriesSchemes</key>

lib/main.dart

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import 'package:the_app/src/widgets/menu/dark_theme.dart';
1515
import 'package:the_app/src/widgets/dismiss_keyboard.dart';
1616
import 'package:the_app/src/api.dart';
1717
import 'package:the_app/src/push_notification.dart' as push_notification;
18-
import 'package:the_app/src/uni_links.dart' as uni_links;
1918
import 'package:the_app/src/widgets/menu/dev_tools.dart';
2019
import 'package:timeago/timeago.dart' as timeago;
2120

@@ -25,42 +24,35 @@ void main() async {
2524
DarkTheme? darkTheme;
2625
DevTools? devTools;
2726
FontScale? fontScale;
28-
String? initialLink;
2927
String? initialPath;
3028
WidgetsFlutterBinding.ensureInitialized();
3129
await Future.wait([
3230
DarkTheme.create().then((value) => darkTheme = value),
3331
FontScale.create().then((value) => fontScale = value),
3432
DevTools.create().then((value) => devTools = value),
3533
facebook_log_in.configureFacebookLogin(),
36-
uni_links.getInitialLink().then((value) => initialLink = value),
3734
firebase.initializeApp().then((value) async {
3835
error_reporting.configureErrorReporting();
3936
push_notification.configurePushNotification();
4037
initialPath = await push_notification.getInitialPath();
4138
}),
4239
]);
4340

44-
Widget? defaultWidget;
45-
String? fallbackLink;
41+
Widget home;
4642
if (initialPath != null) {
47-
defaultWidget = const NotificationListScreen();
48-
} else if (initialLink != null) {
49-
initialPath = buildToolsParseLinkPath(initialLink!);
50-
fallbackLink = initialLink;
43+
home = InitialPathScreen(
44+
initialPath!,
45+
defaultWidget: const NotificationListScreen(),
46+
);
47+
} else {
48+
home = HomeScreen();
5149
}
5250

5351
runApp(MyApp(
5452
darkTheme: darkTheme!,
5553
devTools: devTools!,
5654
fontScale: fontScale!,
57-
home: initialPath != null
58-
? InitialPathScreen(
59-
initialPath!,
60-
defaultWidget: defaultWidget,
61-
fallbackLink: fallbackLink,
62-
)
63-
: HomeScreen(),
55+
home: home,
6456
));
6557
}
6658

@@ -95,7 +87,6 @@ class MyApp extends StatelessWidget {
9587

9688
Widget app = MaterialApp(
9789
darkTheme: _theme(_themeDark),
98-
home: home,
9990
localizationsDelegates: const [
10091
L10nDelegate(),
10192
GlobalCupertinoLocalizations.delegate,
@@ -105,6 +96,39 @@ class MyApp extends StatelessWidget {
10596
navigatorKey: push_notification.primaryNavKey,
10697
navigatorObservers: [FontControlWidget.routeObserver],
10798
onGenerateTitle: (context) => l(context).appTitle,
99+
onGenerateInitialRoutes: (initialRoute) {
100+
if (initialRoute == '/') {
101+
// user (1) launches Android/iOS app
102+
// or (4a) opens link when iOS app is killed
103+
// (the actual route will trigger onGenerateRoute after a few ms)
104+
return [MaterialPageRoute(builder: (_) => home)];
105+
} else {
106+
// (3) user opens link when Android app is killed
107+
return [
108+
MaterialPageRoute(
109+
builder: (_) => InitialPathScreen(
110+
buildToolsParseLinkPath(initialRoute),
111+
defaultWidget: home,
112+
),
113+
),
114+
];
115+
}
116+
},
117+
onGenerateRoute: (settings) {
118+
// user opens link when: (2) Android/iOS app is in background
119+
// or (4b) iOS app is killed
120+
final name = settings.name;
121+
if (name == null) {
122+
debugPrint('onGenerateRoute -> $settings without name');
123+
return null;
124+
}
125+
126+
parsePath(
127+
buildToolsParseLinkPath(name),
128+
rootNavigator: push_notification.primaryNavKey.currentState,
129+
);
130+
return null;
131+
},
108132
showPerformanceOverlay: showPerformanceOverlay,
109133
supportedLocales: const [
110134
Locale('en', ''),
@@ -114,7 +138,6 @@ class MyApp extends StatelessWidget {
114138
);
115139

116140
app = DismissKeyboard(app);
117-
app = uni_links.UniLinksApp(child: app);
118141
app = push_notification.PushNotificationApp(child: app);
119142
app = ApiApp(child: app);
120143

lib/src/abstracts/uni_links.dart

Lines changed: 0 additions & 16 deletions
This file was deleted.

lib/src/push_notification.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ import 'package:the_app/src/link.dart';
1111
const _kUnreadIconSize = 30.0;
1212
const _kUnreadIconBoxSize = 50.0;
1313

14-
final primaryNavKey = GlobalKey<NavigatorState>();
14+
final primaryNavKey = GlobalKey<NavigatorState>(
15+
debugLabel: 'push_notification.primaryNavKey',
16+
);
1517

16-
final _key = GlobalKey<_PushNotificationAppState>();
18+
final _key = GlobalKey<_PushNotificationAppState>(
19+
debugLabel: 'push_notification._key',
20+
);
1721
final StreamController<int> _notifController = StreamController.broadcast();
1822

1923
void configurePushNotification() {

lib/src/uni_links.dart

Lines changed: 0 additions & 60 deletions
This file was deleted.

lib/src/widgets/menu/availability/uni_links.dart

Lines changed: 0 additions & 17 deletions
This file was deleted.

lib/src/widgets/menu/dev_tools.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import 'package:the_app/src/intl.dart';
88
import 'availability/error_reporting.dart';
99
import 'availability/firebase.dart';
1010
import 'availability/push_notification.dart';
11-
import 'availability/uni_links.dart';
1211

1312
class DevTools extends ChangeNotifier {
1413
bool? _isDeveloper;
@@ -54,8 +53,8 @@ class DeveloperMenu extends StatelessWidget {
5453
builder: (_, developer, __) => developer.isDeveloper
5554
? ListTile(
5655
title: Text(l(context).menuDeveloper),
57-
onTap: () => Navigator.of(context).push(
58-
MaterialPageRoute(builder: (_) => const DeveloperMenuScreen())),
56+
onTap: () => Navigator.of(context).push(MaterialPageRoute(
57+
builder: (_) => const DeveloperMenuScreen())),
5958
)
6059
: const SizedBox.shrink(),
6160
);
@@ -74,7 +73,6 @@ class DeveloperMenuScreen extends StatelessWidget {
7473
const ErrorReportingWidget(),
7574
const FirebaseWidget(),
7675
const PushNotificationWidget(),
77-
const UniLinksWidget(),
7876
_ShowPerformanceOverlayWidget(),
7977
_CrashTestWidget(),
8078
],

0 commit comments

Comments
 (0)