将 UniLinks 与 Flutter 集成(安卓 AppLinks + iOS UniversalLinks)

让我们使用 Flutter Mobile 和 Flutter Web 集成 UniLinks。

一步一步的指导!

我是 Pedro Dionísio,是葡萄牙 InspireIT 公司的 Flutter 开发人员,我写这个 UniLinks 教程的座右铭是:

  1. Firebase DynamicLinks 已被弃用,就像 Firebase 在其文档中所说,不应再实现(我正在使用它,由于它有一些错误并且已被弃用,我决定开始将这种类型的 Deeplink 迁移到 UniLinks);
  2. 这种 Deeplink 方法被 TikTok、Instagram、Facebook 等大公司使用……
  3. 我在某些特定的 Android 设备上实现它时遇到了一些问题(尝试打开并将数据传递给应用程序)。

因此,我将把所有步骤讲得一清二楚,并且解释一切,不仅适用于 Flutter Android 和 iOS,还适用于 Flutter Web 和 Firebase WebHosting,以免错过任何步骤。让我们开始吧!

Deep Linking 介绍

什么是 Deep Linking?

Deep Linking(深层链接)就像有一个指向应用程序某些部分的快捷方式。

这是一种特殊的网络链接,它不仅可以打开您的应用程序,还可以将您带到应用程序内的特定位置。就像打开一本书,直接翻到您想阅读的页面一样。

它是如何工作的?

假设您在应用程序中发现了一篇很棒的文章,并且想与朋友分享。您可以向他们发送一个特殊的链接,将他们直接带到该文章,而不是将他们发送到应用程序的主页并要求他们查找该文章。这就像给他们送了一条秘密通道。

最酷的部分是什么?

最酷的是,您还可以通过此链接发送特殊说明或代码。例如,如果应用程序中有折扣码或隐藏的惊喜,您可以将其包含在链接中。所以,你不仅能很快到达正确的地方,还能得到一些额外的好处。

如果应用程序已经打开会发生什么?

有时,当您单击深层链接时,您的应用程序可能已经打开。不用担心!当应用程序已经运行时,深度链接甚至可以工作。这就像切换到您正在阅读的书中的正确页面。

关于 UniLinks 的一些最后说明

在本教程中,我将向您展示如何使用名为“uni_links”的工具使深度链接变得超级简单。

重要的是,在这种类型的深层链接中,必须在网站中分配 2 个配置文件(一个用于 Android,一个用于 iOS)。其含义是因为这些文件存储有关您的应用程序的重要信息,并且通过它们,您的网络浏览器可以准确地知道在手机内重定向到哪里。

说到这里,我将向您展示如何创建 Flutter Web 项目并将这些文件放置在正确的位置。

完全不用担心!这将很容易实施!让我们开始吧!📱🚀

为您的移动应用创建 Flutter 项目

Android 配置

转到项目的 android/app/src/main/AndroidManifest.xml 文件。

在这里,我们需要更改一些内容,首先将 android:launchMode="singleTop" 替换为 android:launchMode="singleTask" ,因为我们只希望在手机中打开 APP 的一个实例。

应该会出现这样的内容:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"><application ...><activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTask" <!-- <----HERE---- -->...>

之后,在同一个文件中,您需要配置您的“APP 入口”,该入口将通过特定的 UniLink 进行。

例如我们希望通过这个链接打开 APP: https://mypage.web.app/promos/?promo-id=ABC1 。

因此,在 activity 内,您将添加一个 intent-filter ,如下所示:

<manifest ...><application ...><activity ...>...<!-- App Links --><intent-filter android:autoVerify="true"><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><dataandroid:scheme="https"android:host="mypage.web.app"android:pathPrefix="/promos/" /></intent-filter>...</activity></application>
</manifest>

iOS 配置

使用相同的示例,我们希望通过此链接打开应用程序: https://mypage.web.app/promos/?promo-id=ABC1 。

转到项目的 ios/Runner/Runner.entitlements 文件并添加以下 keyarray 标记:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>...<key>com.apple.developer.associated-domains</key><array><string>applinks:mypage.web.app</string></array>...
</dict>
</plist>

您不需要这样做,但如果您愿意,您也可以通过 XCode 进行此配置:

  • 双击 ios/Runner.xcworkspace 文件打开 Xcode;
  • 转到项目导航器 (Cmd+1) 并选择最顶部的 Runner 根项目;
  • 选择 Runner 目标,然后选择 Signing & Capabilities 选项卡;
  • 单击 + Capability (加号)按钮添加新功能;
  • 输入 associated domains 并选择该项目;
  • 双击域列表中的第一项,将其从 webcredentials:example.com 更改为:applinks:mypage.web.app
  • 将创建一个名为 Runner.entitlements 的文件并将其添加到项目中。

Flutter 实现

我通常使用模块化的方法来组织一切,但对于这个示例项目,我将进行混合,使一切变得简单直观。

让我们首先在此处获取最新版本的 uni_links 包:https://pub.dev/packages/uni_links 并将其粘贴到项目的 pubspec.yaml 文件中,如下所示:

---
dependencies:flutter:sdk: fluttercupertino_icons: ^1.0.2uni_links: ^0.5.1 # <----------------

保存并执行 flutter pun get 以更新您的项目依赖项。

然后添加三个用户界面文件: 主屏幕、绿色宣传屏幕和红色宣传屏幕。

主屏幕文件 lib/screens/home_screen.dart

import 'package:flutter/material.dart';class HomeScreen extends StatelessWidget {const HomeScreen({super.key});Widget build(BuildContext context) {return Scaffold(body: Container(alignment: Alignment.center,child: const Text("Home Screen",style: TextStyle(fontSize: 24,fontWeight: FontWeight.bold,),),),);}
}

绿色促销屏幕文件 lib/screens/green_promo_screen.dart

import 'package:flutter/material.dart';
import 'package:unilinkproject/common/uni_links/core/services/uni_links_service.dart';class GreenPromoScreen extends StatelessWidget {const GreenPromoScreen({super.key});Widget build(BuildContext context) {return Scaffold(body: Container(alignment: Alignment.center,decoration: const BoxDecoration(gradient: LinearGradient(colors: [Colors.green,Colors.greenAccent,],begin: Alignment.topRight,end: Alignment.bottomLeft,),),child: Text("!!! Green Promo !!!\nCode: ${UniLinksService.promoId}",textAlign: TextAlign.center,style: const TextStyle(fontSize: 24,fontWeight: FontWeight.bold,),),),);}
}

红色促销屏幕 lib/screens/red_promo_screen.dart

import 'package:flutter/material.dart';
import 'package:unilinkproject/common/uni_links/core/services/uni_links_service.dart';class RedPromoScreen extends StatelessWidget {const RedPromoScreen({super.key});Widget build(BuildContext context) {return Scaffold(body: Container(alignment: Alignment.center,decoration: const BoxDecoration(gradient: LinearGradient(colors: [Colors.red,Colors.redAccent,],begin: Alignment.topRight,end: Alignment.bottomLeft,),),child: Text("!!! Red Promo !!!\nCode: ${UniLinksService.promoId}",textAlign: TextAlign.center,style: const TextStyle(fontSize: 24,fontWeight: FontWeight.bold,),),),);}
}

为什么是 3 个屏幕?这是因为我们要测试 3 种情况:

  • APP 正常打开时显示主屏幕;
  • 当我们收到 Unilink https://mypage.web.app/promos/?promo-id=ABC1 时,会显示绿色促销屏幕;
  • 当我们收到 UniLink https://mypage.web.app/promos/?promo-id=ABC2 时,会显示红色促销屏幕。

现在让我们添加一个我在项目中经常使用的重要实用程序文件。有了它我们就可以在 APP 的任何地方访问最新的 BuildContext

添加此文件 lib/common/global_context/utils/contect_utility.dart

import 'package:flutter/material.dart';class ContextUtility {static final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>(debugLabel: 'ContextUtilityNavigatorKey');static GlobalKey<NavigatorState> get navigatorKey => _navigatorKey;static bool get hasNavigator => navigatorKey.currentState != null;static NavigatorState? get navigator => navigatorKey.currentState;static bool get hasContext => navigator?.overlay?.context != null;static BuildContext? get context => navigator?.overlay?.context;
}

接下来我们添加负责处理 UniLinks lib/common/global_context/utils/context_utility.dart 的文件:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:uni_links/uni_links.dart';
import 'package:unilinkproject/common/global_context/utils/context_utility.dart';
import 'package:unilinkproject/screens/green_promo_screen.dart';
import 'package:unilinkproject/screens/red_promo_screen.dart';class UniLinksService {static String _promoId = '';static String get promoId => _promoId;static bool get hasPromoId => _promoId.isNotEmpty;static void reset() => _promoId = '';static Future<void> init({checkActualVersion = false}) async {// 这用于以下情况:应用程序未运行,用户单击链接。try {final Uri? uri = await getInitialUri();_uniLinkHandler(uri: uri);} on PlatformException {if (kDebugMode) print("(PlatformException) Failed to receive initial uri.");} on FormatException catch (error) {if (kDebugMode) print("(FormatException) Malformed Initial URI received. Error: $error");}// 这用于以下情况:应用程序已经在运行,用户单击链接。uriLinkStream.listen((Uri? uri) async {_uniLinkHandler(uri: uri);}, onError: (error) {if (kDebugMode) print('UniLinks onUriLink error: $error');});}static Future<void> _uniLinkHandler({required Uri? uri}) async {if (uri == null || uri.queryParameters.isEmpty) return;Map<String, String> params = uri.queryParameters;String receivedPromoId = params['promo-id'] ?? '';if (receivedPromoId.isEmpty) return;_promoId = receivedPromoId;if (_promoId == 'ABC1') {ContextUtility.navigator?.push(MaterialPageRoute(builder: (_) => const GreenPromoScreen()),);}if (_promoId == 'ABC2') {ContextUtility.navigator?.push(MaterialPageRoute(builder: (_) => const RedPromoScreen()),);}}
}

最后我们将 main.dart 文件更改为:

import 'package:flutter/material.dart';
import 'package:unilinkproject/common/uni_links/core/services/uni_links_service.dart';
import 'package:unilinkproject/common/global_context/utils/context_utility.dart';
import 'package:unilinkproject/screens/green_promo_screen.dart';
import 'package:unilinkproject/screens/home_screen.dart';
import 'package:unilinkproject/screens/red_promo_screen.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();await UniLinksService.init();runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(navigatorKey: ContextUtility.navigatorKey,debugShowCheckedModeBanner: false,title: 'UniLinks Project',routes: {'/': (_) => const HomeScreen(),'/green-promo': (_) => const GreenPromoScreen(),'/red-promo': (_) => const RedPromoScreen(),},);}
}

我们就完成了!

您可以测试正常打开 APP,查看是否出现主屏幕。


原文:https://medium.com/@pedrostick3/integrate-unilinks-with-flutter-android-applinks-ios-universallinks-c9a1542d6625

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/179909.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Goland 对容器中的 Go 程序断点远程调试

1&#xff0c;针对 golang 程序打断点有哪几种情况 临时进程&#xff1a;针对临时运行一次的 Golang 脚本&#xff0c;比如定时统计脚本&#xff0c;定时推送脚本。常驻进程&#xff1a;针对一直在后台运行的 Golang 程序&#xff0c;比如 HTTP 或者 GRPC 服务。 我们现在假设…

QT学习之QT概述

1.1 什么是QT&#xff1f; Qt是一个跨平台的C图形用户界面应用程序框架。 QT特点&#xff1a; 跨平台&#xff0c;几乎支持所有的平台接口简单&#xff0c;容易上手&#xff0c;学习QT框架对学习其他框架有参考意义。一定程度上简化了内存回收机制开发效率高&#xff0c;能够…

react+canvas实现横跨整个页面的动态的波浪线(贝塞尔曲线)

本来写这个特效 我打算用css实现的&#xff0c;结果是一波三折&#xff0c;我太难了&#xff0c;最终没能用css实现&#xff0c;转战了canvas来实现。来吧先看效果图 当然这个图的波浪高度、频率、位置、速度都是可调的&#xff0c;请根据自己的需求调整&#xff0c;如果你讲波…

【Nginx38】Nginx学习:SSL模块(二)错误状态码、变量及宝塔配置分析

Nginx学习&#xff1a;SSL模块&#xff08;二&#xff09;错误状态码、变量及宝塔配置分析 继续我们的 SSL 模块的学习。上回其实我们已经搭建起了一个 HTTPS 服务器了&#xff0c;只用了三个配置&#xff0c;其中一个是 listen 的参数&#xff0c;另外两个是指定密钥文件的地址…

Rust语言和curl库编写程序

这是一个使用Rust语言和curl库编写的爬虫程序&#xff0c;用于爬取视频。 use std::env; use std::net::TcpStream; use std::io::{BufReader, BufWriter}; ​ fn main() {// 获取命令行参数let args: Vec<String> env::args().collect();let proxy_host args[1].clon…

MobaXterm使用VNC远程显示和控制ubuntu桌面

目录 1 在ubuntu中安装vnc 2 设置ubuntu远程连接 3 MobaXterm中连接ubuntu的vnc 1 在ubuntu中安装vnc 参考&#xff1a;Ubuntu18.04~Ubuntu22.04安装并配置VNC_ubuntu安装vnc-CSDN博客 大体流程就是在ubuntu中安装vnc&#xff0c;设置密码&#xff0c;然后配置服务&#x…

linux+python3.6.8+uwsgi+postgresql+django部署web服务器

linuxpython3.6.8uwsgipostgresqldjango部署web服务器 1.查看系统信息2.配置postgresql数据库2-1.安装postgresql数据库2-2.设置密码2-3.修改postgresql数据库配置文件 3.Python虚拟环境激活虚拟环境 4.Django4-1.Python 安装Django4-2.创建Django项目4-3.配置Django 5.uwsgi5-…

基于python+django+vue开发的酒店预订管理系统 - 毕业设计 - 课程设计

文章目录 源码下载地址项目介绍项目功能界面预览项目备注毕设定制&#xff0c;咨询 源码下载地址 点击这里下载源码 项目介绍 该系统是基于pythondjango开发的酒店预定管理系统。适用场景&#xff1a;大学生、课程作业、毕业设计。学习过程中&#xff0c;如遇问题可在github…

CSS3设计动画样式

CSS3动画包括过渡动画和关键帧动画&#xff0c;它们主要通过改变CSS属性值来模拟实现。我将详细介绍Transform、Transitions和Animations 3大功能模块&#xff0c;其中Transform实现对网页对象的变形操作&#xff0c;Transitions实现CSS属性过渡变化&#xff0c;Animations实现…

ChatGPT 实际上是如何工作的?

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; ChatGPT 操作的两个主要阶段 我们再用谷歌来打个比方。当你要求谷歌查找某些内容时&#xff0c;你可能知道它不会——在你提出要求的那一刻——出去搜索整个网络来寻找答案。相反&#xff0c;谷歌会在其数…

网络编程套接字(二)

目录 简单的TCP网络程序服务端创建套接字服务端绑定服务端监听服务端获取连接服务端处理请求单执行流服务器的弊端 多进程版TCP网络程序捕捉SIGCHLD信号让孙子进程提供服务多线程版的TCP网络程序客户端创建套接字客户端链接服务器客户端发起请求 线程池版的TCP网络程序 简单的T…

IntelliJ IDEA 2023 最新版如何试用?IntelliJ IDEA 2023最新版试用方法及验证ja-netfilter配置成功提示

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Rocky9 上安装 redis-dump 和redis-load 命令

一、安装依赖环境 1、依赖包 dnf -y install perl gcc gcc-c zlib-devel2、编译openssl 1.X ### 下载编译 wget https://www.openssl.org/source/openssl-1.1.1t.tar.gz tar xf openssl-1.1.1t.tar.gz cd openssl-1.1.1t ./config --prefix/usr/local/openssl make make ins…

Ubuntu重启后进入initramfs导致无法开机解决方案

今天&#xff0c;我的电脑意外关机&#xff0c;重新开机后打开了虚拟机。该虚拟机使用的是 Ubuntu 22.04 系统。但重启后&#xff0c;系统一直显示(initramfs):&#xff0c;导致无法正常启动。最后&#xff0c;在网上查找了一些解决方案&#xff0c;成功解决了这个开机问题。在…

Java配置47-Spring Eureka 未授权访问漏洞修复

文章目录 1. 背景2. 方法2.1 Eureka Server 添加安全组件2.2 Eureka Server 添加参数2.3 重启 Eureka Server2.4 Eureka Server 升级版本2.5 Eureka Client 配置2.6 Eureka Server 添加代码2.7 其他问题 1. 背景 项目组使用的 Spring Boot 比较老&#xff0c;是 1.5.4.RELEASE…

Minium:专业的小程序自动化工具

小程序架构上分为渲染层和逻辑层&#xff0c;尽管各平台的运行环境十分相似&#xff0c;但是还是有些许的区别&#xff08;如下图&#xff09;&#xff0c;比如说JavaScript 语法和 API 支持不一致&#xff0c;WXSS 渲染表现也有不同&#xff0c;所以不论是手工测试&#xff0c…

腾讯云双十一云服务器活动:88元1年的云服务器难道不香吗?

腾讯云双十一活动中&#xff0c;有三款轻量应用服务器可享受特惠优惠。这三款服务器分别是2核2G、2核4G和4核8G&#xff0c;价格分别为88元/年、166.6元/年和529元/15个月。对于需要低成本而又高性能的服务器需求&#xff0c;轻量应用服务器是一个理想的选择。 轻量应用服务器特…

【错误解决方案】matplotlib绘图中文标签不显示

1. 错误提示 Matplotlib 中文标签不显示的问题通常是由于中文字符在图形中的编码问题导致的。例如&#xff1a; import numpy import matplotlib.pyplot as pltz numpy.arange(-5, 5, .1) sigma_fn numpy.vectorize(lambda z: 1/(1numpy.exp(-z))) sigma sigma_fn(z)fig …

中国等28个国家发布《布莱切利宣言》,鼓励AI以安全方式发展

英国时间11月1日&#xff0c;中国、美国、英国、法国、德国等28个国家和欧盟&#xff0c;在英国的布莱切利庄园签署了&#xff0c;首个全球性人工智能&#xff08;AI&#xff09;声明——《布莱切利宣言》。 该宣言明确指出了AI对人类社会的巨大机遇&#xff0c;但AI需要以人为…

【C语法学习】11 - fprintf()函数

文章目录 1 函数原型2 参数3 返回值4 比较5 示例 1 函数原型 fprintf()&#xff1a;将格式化输出发送至指定流stream&#xff0c;函数原型如下&#xff1a; int fprintf(FILE *stream, const char *format, ...)2 参数 fprintf()函数参数包括三部分&#xff1a; 参数stream…