Skip to content

Commit

Permalink
fix: launch urls and catch errors
Browse files Browse the repository at this point in the history
Using `canLaunch` within flatpak seems to fail, so we catch the error and
 return false instead.

flutter/flutter#88463
  • Loading branch information
Merrit committed Feb 2, 2023
1 parent bc1245f commit 29f8e26
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 36 deletions.
23 changes: 15 additions & 8 deletions lib/app/cubit/app_cubit.dart
@@ -1,25 +1,34 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;

import '../../logs/logs.dart';
import '../../storage/storage_repository.dart';
import '../../url_launcher/url_launcher.dart';

part 'app_state.dart';

/// A function that launches a [url] in the default browser.
typedef LaunchUrl = Future<bool> Function(
Uri url, {
url_launcher.LaunchMode mode,
url_launcher.WebViewConfiguration webViewConfiguration,
String? webOnlyWindowName,
});

/// Handles general app-related functionality, like launching urls and checking
/// for app updates.
class AppCubit extends Cubit<AppState> {
final StorageRepository _storageRepository;
final UrlLauncher _urlLauncher;
final LaunchUrl _launchUrl;

static late AppCubit instance;

AppCubit(
this._storageRepository,
this._urlLauncher,
) : super(AppState.initial()) {
this._storageRepository, [
LaunchUrl? launchUrl,
]) : _launchUrl = launchUrl ?? url_launcher.launchUrl,
super(AppState.initial()) {
instance = this;
init();
}
Expand Down Expand Up @@ -47,10 +56,8 @@ class AppCubit extends Cubit<AppState> {
return false;
}

if (!await _urlLauncher.canLaunch(uri)) return false;

try {
return await _urlLauncher.launch(uri);
return await _launchUrl(uri);
} on PlatformException catch (e) {
log.e('Could not launch url: $url', e);
return false;
Expand Down
6 changes: 1 addition & 5 deletions lib/main.dart
Expand Up @@ -22,7 +22,6 @@ import 'settings/cubit/settings_cubit.dart';
import 'storage/storage_repository.dart';
import 'system_tray/system_tray_manager.dart';
import 'theme/theme.dart';
import 'url_launcher/url_launcher.dart';
import 'window/app_window.dart';

Future<void> main(List<String> args) async {
Expand Down Expand Up @@ -76,10 +75,7 @@ Future<void> main(List<String> args) async {
MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AppCubit(
storage,
UrlLauncher(),
),
create: (context) => AppCubit(storage),
lazy: false,
),
BlocProvider.value(value: settingsCubit),
Expand Down
1 change: 0 additions & 1 deletion lib/url_launcher/src/src.dart

This file was deleted.

8 changes: 0 additions & 8 deletions lib/url_launcher/src/url_launcher.dart

This file was deleted.

1 change: 0 additions & 1 deletion lib/url_launcher/url_launcher.dart

This file was deleted.

34 changes: 21 additions & 13 deletions test/app/cubit/app_cubit_test.dart
@@ -1,31 +1,40 @@
import 'package:flutter/services.dart';
import 'package:mocktail/mocktail.dart';
import 'package:nyrna/app/app.dart';
import 'package:nyrna/logs/logs.dart';
import 'package:nyrna/storage/storage_repository.dart';
import 'package:nyrna/url_launcher/url_launcher.dart';
import 'package:test/test.dart';
import 'package:url_launcher/url_launcher.dart' as url_launcher;

class MockStorageRepository extends Mock implements StorageRepository {}

class MockUrlLauncher extends Mock implements UrlLauncher {}
class MockLaunchUrl extends Mock {
Future<bool> call(
Uri url, {
url_launcher.LaunchMode mode,
url_launcher.WebViewConfiguration webViewConfiguration,
String? webOnlyWindowName,
});
}

late AppCubit cubit;
AppState get state => cubit.state;

void main() {
late StorageRepository storageRepository;
late UrlLauncher urlLauncher;
late LaunchUrl urlLauncher;

setUpAll(() {
setUpAll(() async {
registerFallbackValue(Uri());
await LoggingManager.initialize(verbose: false);
});

setUp(() {
storageRepository = MockStorageRepository();
when(() => storageRepository.getValue(any())).thenAnswer((_) async => null);

urlLauncher = MockUrlLauncher();
when(() => urlLauncher.canLaunch(any())).thenAnswer((_) async => true);
when(() => urlLauncher.launch(any())).thenAnswer((_) async => true);
urlLauncher = MockLaunchUrl();
when(() => urlLauncher.call(any())).thenAnswer((_) async => true);

cubit = AppCubit(
storageRepository,
Expand All @@ -45,18 +54,17 @@ void main() {
test('launches a correct url', () async {
final result = await cubit.launchURL(correctTestUrl);
expect(result, true);
verify(() => urlLauncher.canLaunch(any())).called(1);
verify(() => urlLauncher.launch(any())).called(1);
verify(() => urlLauncher.call(any())).called(1);
});

test('bad url returns false', () async {
const badTestUrl = 'htp:/gogg.m';
when(() => urlLauncher.canLaunch(Uri.parse(badTestUrl)))
.thenAnswer((_) async => false);
final uri = Uri.parse(badTestUrl);
when(() => urlLauncher.call(uri))
.thenThrow(PlatformException(code: 'bad url'));
final result = await cubit.launchURL(badTestUrl);
expect(result, false);
verify(() => urlLauncher.canLaunch(any())).called(1);
verifyNever(() => urlLauncher.launch(any()));
verify(() => urlLauncher.call(any())).called(1);
});
});
});
Expand Down

0 comments on commit 29f8e26

Please sign in to comment.