4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

flutterのwebview_flutterでリンクをアプリ内ブラウザで開きたい場合の注意点

Posted at

概要

webview_flutterで特定リンクをアプリ内ブラウザで開く場合に、ホワイトリストやブラックリストを作って、アプリ内ブラウザを開く開かないの対応をすると思います。
その際に意図しないURLまでアプリ内ブラウザで開いてしまったので、その際に対応した内容を記載します。

アプリ内ブラウザを開く際にはurl_launcherを利用しています。

環境

> flutter doctor                                                                           
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.17.5, on Mac OS X 10.15.5 19F101, locale ja-JP)
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    ✗ Android license status unknown.
      Try re-installing or updating your Android SDK Manager.
      See https://developer.android.com/studio/#downloads or visit visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions.
[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
[✓] Android Studio (version 3.6)
[✓] VS Code (version 1.46.1)
  • webview_flutter: ^0.3.21
  • url_launcher: ^5.4.7

実装内容

不要な部分は省略しています

main.dart

main.dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
            child: WebView(
          navigationDelegate:
              // providerを使用しています
              context.watch<WebViewViewmodel>().onNavigationDelegate,
        )),
        bottomNavigationBar: BottomNavigationWidget());
  }

WebViewViewmodelの実装内容

WebViewViewmodel.dart
  NavigationDecision onNavigationDelegate(NavigationRequest request) {
    // request.urlに遷移先のURLが入ってくる
    if (request.url == 'アプリ内ブラウザで開きたくない対象のURL') {
      // navigateで通常のwebview内で遷移
      return NavigationDecision.navigate;
    } else {
      log(request.url);
      // アプリ内ブラウザで開きたい場合はurl_launcherを利用する
      _launchBrowser(request.url);
      return NavigationDecision.prevent;
    }
  }

  // 詳細はurl_launcherの実装方法を参照
  Future<void> _launchBrowser(String url) async {
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw ArgumentError('Could not launch $url');
    }
  }

問題点

実はこれだと問題がでてきます。
それはiframeやlink rel="xxx"で指定されるURLも判定対象になるためです。
iframeのURLやCSSのlink relの要素もnavigationDelegateの処理に入ってきます。
そのため、意図しないURLもアプリ内ブラウザで開いてしまう可能性があります。

解決策

request.isForMainFrameを利用します

WebViewViewmodel.dart
  NavigationDecision onNavigationDelegate(NavigationRequest request) {
    // request.isForMainFrameではない場合はwebviewでの遷移として扱う
    if (!request.isForMainFrame) return NavigationDecision.navigate;
    // ...略
  }

名前の通り、isForMainFrameは遷移先のメインURLかどうかを判定してくれます。
iframeやlink relなどのURLの場合はfalseが入るのでこれで対応できました。


皆さんの参考になれば幸いです。

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?