Skip to content

Commit

Permalink
feat: Better support deep links with unsupported URLs (#4007)
Browse files Browse the repository at this point in the history
* Better support for external links

* Change the import we use
  • Loading branch information
g123k committed May 24, 2023
1 parent 12083f1 commit d5d86b4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 16 deletions.
31 changes: 20 additions & 11 deletions packages/smooth_app/lib/pages/navigator/app_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ class AppNavigator extends InheritedWidget {
///
/// All our routes are prefixed with an underscore, as the [redirect] method
/// is also called with non prefixed paths for deep links.
///
/// One drawback of the implementation is that we never know the base URL of the
/// deep link (eg: es.openfoodfacts.org)
class _SmoothGoRouter {
_SmoothGoRouter({
List<NavigatorObserver>? observers,
Expand Down Expand Up @@ -165,9 +168,9 @@ class _SmoothGoRouter {
},
),
GoRoute(
path: '${_InternalAppRoutes.EXTERNAL_PAGE}/:path',
path: _InternalAppRoutes.EXTERNAL_PAGE.path,
builder: (BuildContext context, GoRouterState state) {
return ExternalPage(path: state.pathParameters['path']!);
return ExternalPage(path: state.queryParameters['path']!);
},
),
],
Expand Down Expand Up @@ -202,16 +205,11 @@ class _SmoothGoRouter {
} else {
return AppRoutes.PRODUCT_LOADER(barcode);
}
} else {
return _openExternalLink(path);
}
} else if (path != _InternalAppRoutes.HOME_PAGE.path) {
AnalyticsHelper.trackEvent(
AnalyticsEvent.genericDeepLink,
);

// Unsupported link -> open the browser
return AppRoutes.EXTERNAL(
path[0] == '/' ? path.substring(1) : path,
);
return _openExternalLink(path);
}
}

Expand All @@ -223,6 +221,17 @@ class _SmoothGoRouter {
);
}

String _openExternalLink(String path) {
AnalyticsHelper.trackEvent(
AnalyticsEvent.genericDeepLink,
);

// Unsupported link -> open the browser
return AppRoutes.EXTERNAL(
path[0] == '/' ? path.substring(1) : path,
);
}

late GoRouter router;

// Indicates whether [_initAppLanguage] was already called
Expand Down Expand Up @@ -342,5 +351,5 @@ class AppRoutes {

// Open an external link (where path is relative to the OFF website)
static String EXTERNAL(String path) =>
'/${_InternalAppRoutes.EXTERNAL_PAGE}/$path';
'/${_InternalAppRoutes.EXTERNAL_PAGE}/?path=$path';
}
49 changes: 44 additions & 5 deletions packages/smooth_app/lib/pages/navigator/external_page.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:path/path.dart' as path;
import 'package:smooth_app/helpers/launch_url_helper.dart';
import 'package:smooth_app/pages/navigator/app_navigator.dart';
import 'package:smooth_app/query/product_query.dart';

/// This screen is only used for deep links!
///
/// A screen opening a [path] relative to the OFF website.
/// Eg: if path is "contact", it will open 'https://world.openfoodfacts.org/contact'
///
/// Unfortunately the deep link we receive doesn't contain the base URL
/// (eg: de.openfoodfacts.org), that's why we try to guess it with the country
/// and the locale of the user
class ExternalPage extends StatefulWidget {
const ExternalPage({required this.path, Key? key})
: assert(path != ''),
Expand All @@ -22,10 +30,34 @@ class _ExternalPageState extends State<ExternalPage> {
super.initState();

WidgetsBinding.instance.addPostFrameCallback((_) async {
await LaunchUrlHelper.launchURL(
path.join('https://world.openfoodfacts.org', widget.path),
false,
);
// First let's try with https://{country}.openfoodfacts.org
final OpenFoodFactsCountry? country = ProductQuery.getCountry();

String? url;
if (country != null) {
url = path.join(
'https://${country.offTag}.openfoodfacts.org',
widget.path,
);

if (await _testUrl(url)) {
url = null;
}
}

// If that's not OK, let's try with world.openfoodfacts.org?lc={language}
if (url == null) {
final OpenFoodFactsLanguage language = ProductQuery.getLanguage();

url = path.join(
'https://world.openfoodfacts.org',
widget.path,
);

url = '$url?lc=${language.offTag}';
}

await LaunchUrlHelper.launchURL(url, false);

if (mounted) {
AppNavigator.of(context).pop();
Expand All @@ -37,4 +69,11 @@ class _ExternalPageState extends State<ExternalPage> {
Widget build(BuildContext context) {
return const Scaffold();
}

/// Check if an URL exist
Future<bool> _testUrl(String url) {
return http
.head(Uri.parse(url))
.then((http.Response value) => value.statusCode != 404);
}
}

0 comments on commit d5d86b4

Please sign in to comment.