【Flutter】【widget】url_launcher 启动其他功能,调用其他app

package:url_launcher

有时候需要在app 内进行一些跳转功能,比如需要点击一个按键然后跳转到邮箱页面,并且带着收件人的信息,可以使用该package
地址:https://pub.flutter-io.cn/packages/url_launcher

支持情况:(平台支持的功能可能不一样)

AndroidiOSLinuxmacOSWebWindows
SDK 16+9.0+Any10.11+AnyWindows 10+

功能:

功能:

  1. 应用内打开web
  2. 跳转到web 页面
  3. 打开电话
  4. 打开邮箱
  5. 跳转到其他的应用界面
  6. 打开之后定时返回
  7. 等等功能

使用实例和代码:

权限添加 IOS

在 Info.plist 文件里面添加如下

<key>LSApplicationQueriesSchemes</key>
<array>
 <string>sms</string>
 <string>tel</string>
</array>
权限添加 android

在 AndroidManifest.xml 里面添加

<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
 <!-- If your app checks for SMS support -->
 <intent>
   <action android:name="android.intent.action.VIEW" />
   <data android:scheme="sms" />
 </intent>
 <!-- If your app checks for call support -->
 <intent>
   <action android:name="android.intent.action.VIEW" />
   <data android:scheme="tel" />
 </intent>
</queries>

放置的位置如图,不要放到activity里面,会导致运行报错

在这里插入图片描述
如果没有网络权限的还需要添加:

   <uses-permission android:name="android.permission.INTERNET" />

android 网络权限手册

代码功能解读



import 'dart:async';

import 'package:flutter/material.dart';
import 'package:url_launcher/link.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
 return MaterialApp(
   title: 'URL Launcher',
   theme: ThemeData(
     primarySwatch: Colors.blue,
   ),
   home: const MyHomePage(title: 'URL Launcher'),
 );
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
bool _hasCallSupport = false;
Future<void>? _launched;
String _phone = '';

@override
void initState() {
 super.initState();
 // Check for phone call support.
 canLaunchUrl(Uri(scheme: 'tel', path: '123')).then((bool result) {
   setState(() {
     _hasCallSupport = result;
   });
 });
}

Future<void> _launchInBrowser(Uri url) async {
 //使用默认浏览器打开网页地址 url 网页地址
 if (!await launchUrl(
   url,
   mode: LaunchMode.externalApplication,
 )) {
   throw 'Could not launch $url';
 }
}

Future<void> _launchInWebViewOrVC(Uri url) async {
 //在app 内打开网页,可以添加头部文件
 if (!await launchUrl(
   url,
   mode: LaunchMode.inAppWebView,
   webViewConfiguration: const WebViewConfiguration(
       headers: <String, String>{'my_header_key': 'my_header_value'}),
 )) {
   throw 'Could not launch $url';
 }
}

Future<void> _launchInWebViewWithoutJavaScript(Uri url) async {
 //禁用 JavaScript 的权限 JavaScript OFF
 if (!await launchUrl(
   url,
   mode: LaunchMode.inAppWebView,
   webViewConfiguration: const WebViewConfiguration(enableJavaScript: false),
 )) {
   throw 'Could not launch $url';
 }
}

Future<void> _launchInWebViewWithoutDomStorage(Uri url) async {
 //不带dom storage 缓存打开
 if (!await launchUrl(
   url,
   mode: LaunchMode.inAppWebView,
   webViewConfiguration: const WebViewConfiguration(enableDomStorage: false),
 )) {
   throw 'Could not launch $url';
 }
}

Future<void> _launchUniversalLinkIos(Uri url) async {
 //启动APP 功能。可以带参数,如果启动原生的app 失败
 final bool nativeAppLaunchSucceeded = await launchUrl(
   url,
   mode: LaunchMode.externalNonBrowserApplication,
 );
 //启动失败的话就使用应用内的webview 打开
 if (!nativeAppLaunchSucceeded) {
   await launchUrl(
     url,
     mode: LaunchMode.inAppWebView,
   );
 }
}

Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
 if (snapshot.hasError) {
   return Text('Error: ${snapshot.error}');
 } else {
   return const Text('');
 }
}

// map 转为参数
String? encodeQueryParameters(Map<String, String> params) {
 return params.entries
     .map((MapEntry<String, String> e) =>
         '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
     .join('&');
}

Future<void> _openemail(String emailadd,
   {String subjectinfo = "", String bodyinfo = ""}) async {
 //跳转到电话页面。可以带电话号码
 final Uri launchUri = Uri(
     scheme: 'mailto',
     path: emailadd,
     //<String,String>{
     //   "subject":"邮件的正文内容可以在这边编写"
     // }
     query: encodeQueryParameters(
         subjectinfo == null ? {} : {"body": bodyinfo}));
 await launchUrl(launchUri);
}

Future<void> _SMS(String phonenum,
   {String subjectinfo = "", String bodyinfo = ""}) async {
 //跳转到电话页面。可以带电话号码
 final Uri launchUri = Uri(
     scheme: 'sms',
     path: phonenum,
     //<String,String>{
     //   "subject":"邮件的正文内容可以在这边编写"
     // }
     query: encodeQueryParameters({"body": bodyinfo}));
 await launchUrl(launchUri);
}

Future<void> _openFile(String file_add) async {
 //打开文件夹
 final Uri launchUri = Uri(
   scheme: 'file',
   path: file_add,
 );
 await launchUrl(launchUri);
}

Future<void> _makePhoneCall(String phoneNumber) async {
 //跳转到电话页面。可以带电话号码
 final Uri launchUri = Uri(
   scheme: 'tel',
   path: phoneNumber,
 );
 await launchUrl(launchUri);
}

@override
Widget build(BuildContext context) {
 // 如果是使用url的方式,比如没有电话功能,会变成打开网页的功能

 final Uri toLaunch = Uri(scheme: 'https', host: 'www.baidu.com');
 return Scaffold(
   appBar: AppBar(
     title: Text(widget.title),
   ),
   body: ListView(
     children: <Widget>[
       Column(
         mainAxisAlignment: MainAxisAlignment.spaceAround,
         children: <Widget>[
           Padding(
             padding: const EdgeInsets.all(16.0),
             child: TextField(
                 onChanged: (String text) => _phone = text,
                 decoration:
                     const InputDecoration(hintText: '输入电话号码。点击到拨打界面')),
           ),
           ElevatedButton(
             onPressed: _hasCallSupport
                 ? () => setState(() {
                       _launched = _makePhoneCall(_phone);
                     })
                 : null,
             child:
                 _hasCallSupport ? const Text('打电话') : const Text('不知此电话功能'),
           ),
           Padding(
             padding: const EdgeInsets.all(16.0),
             child: Text(toLaunch.toString()),
           ),
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchInBrowser(toLaunch);
             }),
             child: const Text('使用浏览器打开'),
           ),
           const Padding(padding: EdgeInsets.all(16.0)),
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchInWebViewOrVC(toLaunch);
             }),
             child: const Text('app 内打开 web'),
           ),
           const Padding(padding: EdgeInsets.all(16.0)),
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchInWebViewWithoutJavaScript(toLaunch);
             }),
             child: const Text('Launch in app (JavaScript OFF)'),
           ),
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchInWebViewWithoutDomStorage(toLaunch);
             }),
             child: const Text('Launch in app (DOM storage OFF)'),
           ),
           const Padding(padding: EdgeInsets.all(16.0)),

           //打开一个应用,比如打开YouTube ,但是手机没有改应用,或者是打开失败,跳转到浏览器来打开
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchUniversalLinkIos(toLaunch);
             }),
             child: const Text('打开应用失败的情况,使用web 打开该网页'),
           ),
           const Padding(padding: EdgeInsets.all(16.0)),
           // 加一个定时器,应用内打开web 之后,4s 关闭该webview
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _launchInWebViewOrVC(toLaunch);
               Timer(const Duration(seconds: 5), () {
                 print('Closing WebView after 5 seconds...');
                 closeInAppWebView();
               });
             }),
             child: const Text('app 内打开,然后5s之后关闭该网页'),
           ),

           //打开邮箱
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _openemail("LOVEYOU@gmail.com",
                   subjectinfo: '邮件的主题', bodyinfo: '内容就是好好学习天天向上');
             }),
             child: const Text('打开邮箱'),
           ),
           //发送短信
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _SMS("188888888888", bodyinfo: '内容就是好好学习天天向上');
             }),
             child: const Text('短信功能'),
           ),
           //打开文件
           ElevatedButton(
             onPressed: () => setState(() {
               _launched = _openFile(
                   r'F:\my_work\OTA_EXE\can_log\2022-09-24 11 02 13');
             }),
             child: const Text('打开文件夹'),
           ),

           const Padding(padding: EdgeInsets.all(16.0)),
           // Link 功能 widget
           Link(
             uri: Uri.parse(
                 'https://pub.flutter-io.cn/documentation/url_launcher/latest/link/link-library.html'),
             target: LinkTarget.blank, //新建一个page
             builder: (BuildContext ctx, FollowLink? openLink) {
               return TextButton.icon(
                 onPressed: openLink,
                 label: const Text('Link Widget documentation'),
                 icon: const Icon(Icons.read_more),
               );
             },
           ),
           const Padding(padding: EdgeInsets.all(16.0)),

           FutureBuilder<void>(future: _launched, builder: _launchStatus),
         ],
       ),
     ],
   ),
 );
}
}

截图:

在这里插入图片描述


#####手机应用之间的跳转

【IOS 需要配置应用白名单】

QQ: mqq:// 
微信: weixin:// 
'京东': "openApp.jdMobile://",
淘宝: taobao:// 
美团: imeituan:// 
点评: dianping:// 
1号店: wccbyihaodian:// 
支付宝: alipay:// 
微博: sinaweibo:// 
腾讯微博: TencentWeibo:// 
weico微博: weico:// 
知乎: zhihu:// 
豆瓣fm: doubanradio:// 
网易公开课: ntesopen:// 
Chrome: googlechrome:// 
QQ浏览器: mqqbrowser:// 
uc浏览器: ucbrowser:// 
搜狗浏览器: SogouMSE:// 
百度地图: baidumap:// bdmap:// 
优酷: youku:// 
人人: renren:// 
我查查: wcc:// 
有道词典: yddictproapp:// 
微盘: sinavdisk:// 
名片全能王: camcard://
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:url_launcher/link.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'URL Launcher',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'URL Launcher'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _hasCallSupport = false;
  Future<void>? _launched;
  String _phone = '';

  
  void initState() {
    super.initState();
    // Check for phone call support.
    canLaunchUrl(Uri(scheme: 'tel', path: '123')).then((bool result) {
      setState(() {
        _hasCallSupport = result;
      });
    });
  }

  Future<void> _launchInBrowser(Uri url) async {
    //使用默认浏览器打开网页地址 url 网页地址
    if (!await launchUrl(
      url,
      mode: LaunchMode.externalApplication,
    )) {
      throw 'Could not launch $url';
    }
  }

  Future<void> _launchInWebViewOrVC(Uri url) async {
    //在app 内打开网页,可以添加头部文件
    if (!await launchUrl(
      url,
      mode: LaunchMode.inAppWebView,
      webViewConfiguration: const WebViewConfiguration(
          headers: <String, String>{'my_header_key': 'my_header_value'}),
    )) {
      throw 'Could not launch $url';
    }
  }

  Future<void> _launchInWebViewWithoutJavaScript(Uri url) async {
    //禁用 JavaScript 的权限 JavaScript OFF
    if (!await launchUrl(
      url,
      mode: LaunchMode.inAppWebView,
      webViewConfiguration: const WebViewConfiguration(enableJavaScript: false),
    )) {
      throw 'Could not launch $url';
    }
  }

  Future<void> _launchInWebViewWithoutDomStorage(Uri url) async {
    //不带dom storage 缓存打开
    if (!await launchUrl(
      url,
      mode: LaunchMode.inAppWebView,
      webViewConfiguration: const WebViewConfiguration(enableDomStorage: false),
    )) {
      throw 'Could not launch $url';
    }
  }

  Future<void> _launchUniversalLinkIos(Uri url) async {
    //启动APP 功能。可以带参数,如果启动原生的app 失败
    final bool nativeAppLaunchSucceeded = await launchUrl(
      url,
      mode: LaunchMode.externalNonBrowserApplication,
    );
    //启动失败的话就使用应用内的webview 打开
    if (!nativeAppLaunchSucceeded) {
      await launchUrl(
        url,
        mode: LaunchMode.inAppWebView,
      );
    }
  }

  Widget _launchStatus(BuildContext context, AsyncSnapshot<void> snapshot) {
    if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    } else {
      return const Text('');
    }
  }

  Future<void> _makePhoneCall(String phoneNumber) async {
    //跳转到电话页面。可以带电话号码
    final Uri launchUri = Uri(
      scheme: 'tel',
      path: phoneNumber,
    );
    await launchUrl(launchUri);
  }

  Map<String, String> namemap = {
    'QQ': "mqq://",
    '微信': "weixin://",
    '京东':
        "openApp.jdMobile://virtual?params=%7B%22category%22%3A%22jump%22%2C%22des%22%3A%22m%22%2C%22sourceValue%22%3A%22babel-act%22%2C%22sourceType%22%3A%22babel%22%2C%22url%22%3A%22https%3A%2F%2Fu.jd.com%2F3I1C9vl%22%2C%22M_sourceFrom%22%3A%22h5auto%22%2C%22msf_type%22%3A%22auto%22%7D",
    //  "openApp.jdMobile://item.m.jd.com/product/100028779303.html",
    '淘宝':
        "taobao://item.taobao.com/item.html?id=41700658839", //taobao://item.taobao.com/item.html?id=41700658839
    '美团': "imeituan://",
    '支付宝': "alipay://",
    "qq音乐": "qqmusic://"
  };
  List<Widget> makelistwidget() {
    List<Widget> listw = [];
    namemap.forEach((key, value) {
      Widget widgettemp = ElevatedButton(
          onPressed: () async {
            _launchUniversalLinkIos(Uri.parse(value)); // android 正常
          },
          child: Text(key));
      listw.add(widgettemp);
    });

    return listw;
  }

  
  Widget build(BuildContext context) {
    // 如果是使用url的方式,比如没有电话功能,会变成打开网页的功能
    final Uri toLaunch = Uri(scheme: 'https', host: 'www.baidu.com');
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: ListView(children: makelistwidget())

        // <Widget>[
        //   Column(
        //     mainAxisAlignment: MainAxisAlignment.center,
        //     children: <Widget>[
        //       ElevatedButton(
        //           onPressed: () async {
        //             _launchUniversalLinkIos(Uri.parse("mqq://")); // android 正常
        //           },
        //           child: Text('QQ')),
        //     ],
        //   ),
        // ],

        );
  }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值