Flutter外部链接处理插件external_links的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter外部链接处理插件external_links的使用

一个用于处理应用外部链接的包,提供了一个统一的接口来处理推送通知、深度链接、动态链接等。

组件

ExternalLink

ExternalLink 对象表示链接信息。它包含以下属性和方法:

  • title: 链接的标题,通常与推送通知的标题相关联。
  • content: 链接的内容,通常与推送通知的内容相关联。
  • args: 链接的参数,通常与推送通知的参数相关联。
  • uri: 链接的 URI,通常与深度链接的 URI 相关联。
  • authenticationRequired: 是否需要登录才能处理此链接。
  • getHandler: 返回链接的处理器。如果不需要操作处理器,则返回一个 EmptyHandler 实例。
  • mapFactory: 用于从 Map<String, dynamic> 创建链接。尽快分配。
  • uriFactory: 用于从 Uri 创建链接。尽快分配。

示例代码:

class DummyLink extends ExternalLink {
  [@override](/user/override)
  Map<String, dynamic> get args => {};

  [@override](/user/override)
  bool get authenticationRequired => false;

  [@override](/user/override)
  String get content => 'Dummy content! #${Random().nextInt(100000)}';

  [@override](/user/override)
  ExternalLinkHandler getHandler([BuildContext context]) {
    if (context != null) {
      return DummyLinkHandler(context);
    } else {
      return EmptyHandler();
    }
  }

  [@override](/user/override)
  String get title => 'Dummy title!';

  [@override](/user/override)
  Uri get uri => null;
}

ExternalLinkHandler 和 ExternalLinkContextHandler

链接的处理器。用于在处理链接时执行操作。

  • ExternalLinkHandler: 如果你的操作不需要 BuildContext,可以使用这个类。
  • ExternalLinkContextHandler: 如果你的操作需要 BuildContext,可以使用这个类。

示例代码:

class DummyLinkHandler extends ExternalLinkContextHandler {
  DummyLinkHandler(BuildContext context) : super(context);

  [@override](/user/override)
  Future<void> processLinkWithContext(BuildContext context, ExternalLink link) {
    return showDialog(
      context: context,
      builder: (_) => AlertDialog(
        title: Text(link.title ?? ''),
        content: Text(link.content ?? ''),
      ),
    );
  }
}

ExternalLinksAdapter

适配器,用于将信息处理成 ExternalLink,并自动将其加入到 ExternalLinksBloc 的队列中。

示例代码:

class DummyAdapter extends ExternalLinksAdapter {
  [@override](/user/override)
  Future<void> init() async {}

  void triggerDummy(Uri uri) => emit(
        ExternalLink.uriFactory(uri),
      );
}

ExternalLinksBloc

管理链接队列的 Bloc。

示例代码:

BlocProvider<ExternalLinksBloc>(
  create: (_) => ExternalLinksBloc(
    adapters: [
      DummyAdapter()..init(), // 一个适配器用于处理深度链接
    ],
  ),
  child: // 子组件,通常是 MaterialApp
)

ExternalLinksListener

这是一个方便类,监听 ExternalLink 队列并使用它们的处理器进行处理。你可以选择直接监听 ExternalLinksBloc 并决定如何处理收到的链接。

示例代码:

class ExternalLinksListener extends StatelessWidget {
  final Widget child;
  const ExternalLinksListener({
    Key? key,
    required this.child,
  }) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return BlocListener<ExternalLinksBloc, ExternalLinksState>(
      listenWhen: (previous, current) => current is ExternalLinkAvailable,
      listener: (context, state) {
        if (state is ExternalLinkAvailable) {
          BlocProvider.of<ExternalLinksBloc>(context).add(
            ProcessLink(
              processFunction: (link) {
                return link.getHandler(context).processLink(link);
              },
            ),
          );
        }
      },
      child: child,
    );
  }
}

ExternalLink 工厂

ExternalLink 类有两个函数可以用作工厂来创建链接:

  • mapFactory: 用于从 Map<String, dynamic> 创建链接。
  • uriFactory: 用于从 Uri 创建链接。

默认情况下,这些函数返回 null。如果你想使用它们,只需为它们分配一个新的 Function 对象。

考虑事项

虽然一开始可能看起来过于复杂,但在我的经验中,一个能够以简单方式处理应用外部链接的坚实架构,在长期运行中可能是救命稻草。

只需设置你想要接收链接信息的适配器数量,并定义你需要的链接类型。尽管名字叫 Link,你实际上也可以用它作为应用程序内部的通知系统,或者连接到 WebSocket 等。

假设你在管理深度链接,并且目前管理两个 URL。每当需要新的 URL 时,只需定义另一个链接及其处理器,并更新工厂函数以返回该链接。不需要其他任何操作。

我在几个项目(包括企业项目)中使用过这种架构,并证明了其在长期内非常有用。

完整示例

以下是完整的示例代码:

import 'dart:math';

import 'package:external_links/external_links.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() {
  ExternalLink.uriFactory = (uri) {
    if (uri.path == '/dummy') {
      return DummyLink();
    } else {
      return DummierLink();
    }
  };
  runApp(MyApp());
}

class DummyLink extends ExternalLink {
  [@override](/user/override)
  Map<String, dynamic> get args => {};

  [@override](/user/override)
  bool get authenticationRequired => false;

  [@override](/user/override)
  String get content => 'Dummy content! #${Random().nextInt(100000)}';

  [@override](/user/override)
  ExternalLinkHandler getHandler([BuildContext context]) {
    if (context != null) {
      return DummyLinkHandler(context);
    } else {
      return EmptyHandler();
    }
  }

  [@override](/user/override)
  String get title => 'Dummy title!';

  [@override](/user/override)
  Uri get uri => null;
}

class DummierLink extends ExternalLink {
  [@override](/user/override)
  Map<String, dynamic> get args => {};

  [@override](/user/override)
  bool get authenticationRequired => false;

  [@override](/user/override)
  String get content => 'Dummier content! #${Random().nextInt(100000)}';

  [@override](/user/override)
  ExternalLinkHandler getHandler([BuildContext context]) {
    if (context != null) {
      return DummyLinkHandler(context);
    } else {
      return EmptyHandler();
    }
  }

  [@override](/user/override)
  String get title => 'Dummier title!';

  [@override](/user/override)
  Uri get uri => null;
}

class DummyLinkHandler extends ExternalLinkContextHandler {
  DummyLinkHandler(BuildContext context) : super(context);

  [@override](/user/override)
  Future<void> processLinkWithContext(BuildContext context, ExternalLink link) {
    return showDialog(
      context: context,
      builder: (_) => AlertDialog(
        title: Text(link.title ?? ''),
        content: Text(link.content ?? ''),
      ),
    );
  }
}

class DummyAdapter extends ExternalLinksAdapter {
  [@override](/user/override)
  Future<void> init() async {}

  void triggerDummy(Uri uri) => emit(
        ExternalLink.uriFactory(uri),
      );
}

final dummyAdapter = DummyAdapter();

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return BlocProvider<ExternalLinksBloc>(
      create: (_) => ExternalLinksBloc(
        adapters: [
          dummyAdapter..init(),
        ],
      ),
      child: MaterialApp(
        title: 'External Links Demo',
        home: Home(),
      ),
    );
  }
}

class Home extends StatefulWidget {
  [@override](/user/override)
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return ExternalLinksListener(
      child: Scaffold(
        appBar: AppBar(
          title: Text('External links demo'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: () => dummyAdapter.triggerDummy(Uri.parse('http://dummy.dummy/dummy')),
              child: Text('Trigger dummy'),
            ),
            ElevatedButton(
              onPressed: () => dummyAdapter.triggerDummy(Uri.parse('http://dummy.dummy/dummier')),
              child: Text('Trigger dummier'),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter外部链接处理插件external_links的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter外部链接处理插件external_links的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何在Flutter应用中使用external_links插件来处理外部链接的代码示例。external_links插件允许你轻松地在Flutter应用中打开外部链接,无论是Web URL、电子邮件地址还是电话号码等。

首先,你需要在你的pubspec.yaml文件中添加external_links插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  external_links: ^0.4.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter应用中,你可以按照以下方式使用external_links插件来处理外部链接:

1. 导入插件

在你的Dart文件中,导入external_links插件:

import 'package:external_links/external_links.dart';

2. 使用插件

你可以使用ExternalLinks类的方法来打开不同类型的外部链接。以下是一个简单的示例,展示如何在按钮点击时打开一个Web URL、发送电子邮件和拨打电话号码:

import 'package:flutter/material.dart';
import 'package:external_links/external_links.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('External Links Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () async {
                  await ExternalLinks.openUrl("https://www.example.com");
                },
                child: Text('Open Web URL'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () async {
                  await ExternalLinks.sendEmail(["test@example.com"], "Subject", "Body");
                },
                child: Text('Send Email'),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () async {
                  await ExternalLinks.dialPhoneNumber("+1234567890");
                },
                child: Text('Dial Phone Number'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

3. 权限处理

对于拨打电话和发送电子邮件的功能,你可能需要在AndroidManifest.xml中声明相应的权限。例如:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <application
        ...>
        ...
    </application>

</manifest>

注意:在实际应用中,处理拨打电话和发送短信等敏感操作时,应确保遵循相关隐私政策和用户授权机制。

这个示例展示了如何使用external_links插件在Flutter应用中处理不同类型的外部链接。你可以根据需要扩展和修改这个示例。

回到顶部