为了账号安全,请及时绑定邮箱和手机立即绑定

🚀 介绍Stac——一个专为Flutter设计的服务器驱动UI框架

标签:
API 移动开发

精选

用 JSON 创建动态的用户界面,并在几秒内快速更新应用

由 Rahul Bisht 设计

自从2008年AppStore和PlayStore推出以来,手机应用已经存在了相当长的一段时间,至今,市面上已有数以百万计的手机应用。在这段时间里,变化的不仅是应用程序的数量。应用程序变得更加动态、个性化和智能。

但是,有一件事没有变:我们如何推出手机应用。

还是那个枯燥的过程。你提交更新到商店,等待审批(有时还得祈祷它不会卡在审核中),然后希望用户会去更新应用。哦,如果有 bug 出现?欢迎进入紧急修复阶段。唉 叹气 💨

想象一下,如果你能完全摆脱烦人的应用程序更新循环会怎样?想象一下可以实时推送更新,并直接控制用户界面的展示——没有延迟,无需等待审批。这就是服务器驱动的UI的基本理念。

要了解服务端驱动的用户界面,我们先来谈谈传统的方法,即客户端驱动的用户界面

什么是客户驱动的UI设计

在传统的客户驱动的UI方法中,应用程序的UI与其代码紧密相连。基本上,客户端(也就是你的应用)负责所有事情——UI布局、业务逻辑和渲染。想改变一个按钮的外观或添加一个新功能吗?你需要更新代码,测试它,然后提交到应用商店审核。接着就是漫长的等待:等待商店审核通过,再等待用户更新。这听起来熟悉吗?是的,这很令人疲惫。

虽然这种方法可行,但它还是有一些明显的缺点。

  • 缓慢的更新流程: 即使是界面的细微调整也需要完整的更新。
  • 扩展性问题: 管理多个平台变得复杂,因为每个应用都有自己的代码库。
  • 缺乏灵活性: 变化不能即时生效——你必须等待应用商店的审批和用户的反应。
什么是基于服务器的UI(SDUI)?

服务器驱动的用户界面(SDUI)是一种模式,其中用户界面由服务器驱动,而不是硬编码在应用程序本身中。客户端应用程序不再决定渲染什么内容,而是主要关注如何渲染由服务器定义的这些组件。

可以把这想象成浏览器渲染一个网站。浏览器在展示内容前并不知道具体内容——它只知道如何解析并渲染<.HTML>标签。同样地,在SDUI中,应用程序配备了渲染服务器发送的组件的能力,使用户界面更加动态和灵活,完全由服务器控制。

下面来看看服务器驱动的UI是怎么工作的:

  1. 服务器定义应用的用户界面(UI),通常以轻量级格式,例如JSON。
  2. 你的应用作为客户端接收这些定义并动态展示用户界面。
  3. 界面有任何更改吗?只需更新服务器,应用会立即更新——无需重新安装应用!

但是构建服务端驱动的UI确实非常困难——你需要支持大量的Flutter组件,管理复杂的导航,处理网络调用,并高效地管理状态,同时确保无缝兼容和出色性能。这正是Stac大放异彩的时候。

这是 Stac 的介绍 🚀

Stac (曾称为 Mirai),这是一个专为 Flutter 设计的强大 Server-Driven UI (SDUI) 框架。使用 Stac,你可以用 JSON 实时定义 UI,制作出令人惊艳的跨平台应用。注释:Server-Driven UI (SDUI) 是一种由服务器端驱动用户界面的设计模式。

GitHub - StacDev/stac: Stac(原名 Mirai)是一个基于 Flutter 的 SDUI 框架,帮助您创建惊艳的界面…Stac(原名 Mirai)是一个基于 Flutter 的 SDUI 框架,帮助您创建惊艳的界面…github.com

——开始安装Stac

要开始使用Stac,请按照以下安装步骤操作:

在你的 pubspec.yaml 文件中添加这个 Stac 依赖:

运行下面的命令,然后按回车键。

在你的Flutter项目中,运行以下命令来添加依赖:

flutter pub add stac

这会把 Stac 添加到你的 pubspec.yaml 文件,并触发自动的 flutter pub get。

或者,你可以在 pubspec.yaml 文件中手动添加依赖项。

    依赖关系:  
      stac: ^<最新版>

2. 在终端中运行以下命令,来安装这个软件包:

flutter pub get  # 获取依赖包

3. 在你的 Dart 文件里导入 Stac 包

导入 'package:stac/stac.dart';

现在你可以开始在你的 Flutter 项目中使用 Stac。

初始化 Stac

main 函数中,初始化 Stac 来配置必要的设置,并准备好您的应用程序,以便从 JSON 渲染 UI。

void main() async {  
      await Stac.initialize();  
      runApp(const MyApp());  
}

可以使用以下代码来初始化Stac并运行MyApp应用。

就这样好了。现在你的应用已经添加了SDUI支持,你可以使用 Stac.fromJson()Stac.fromAsset()Stac.fromNetwork() 方法来显示UI。

关于Stac JSON的定义

Stac JSONs 被设计得让人感到熟悉,特别是如果你对 Flutter 的小部件结构有了解。实际上,Stac JSONs 本质上就是 Flutter 小部件的 JSON 版本——它们在层次结构和逻辑上与 Flutter 小部件相同,只是格式不同。

这里就是秘诀:如果你会写 Flutter 的部件树,你就可以轻松定义一个 Stac JSON 结构。我们来比较一下:

Flutter 组件:
    Column(
      children: [
        Text("嗨,Stac!"),
        ElevatedButton(
          onPressed: () => print("按钮被按下了"),
          child: Text("点击我"),
        ),
      ],
    )
Stac的JSON等价形式:
{
  "type": "column",
  "children": [
    {
      "type": "text",
      "data": "嗨,Stac!"
    },
    {
      "type": "elevatedButton",
      "onPressed": {
          "action": "print",
          "message": "按钮被点了"
        },
        "child": {
          "type": "text",
          "data": "点我"
        }
    }
  ]
}

看到相似之处了吗?就像把你的 Flutter 小部件转换成 JSON。结构依然清晰易懂,所以你不需要学习全新的编程风格——你只是把 Flutter 代码以 JSON 的形式编写。

Stac的主要好处
  1. 即时UI更新: 无需应对应用更新和商店审批的麻烦。使用SDUI,服务器端的任何更改都会立刻生效,确保您的应用始终处于最新状态。
  2. 轻松个性化: 根据用户的喜好、行为或人口统计数据提供个性化的体验,而无需修改客户端代码。
  3. 简化维护: 在服务器端集中管理UI逻辑,这样可以减少维护多版本应用的复杂性,并确保跨平台更新的一致性。
  4. 轻松A/B测试: 通过从服务器直接提供不同UI版本的载荷,实时测试多个版本。这样可以更快地获得反馈并迭代,而无需额外的开发周期。
  5. 减少开发负担: 将精力集中在后端逻辑上,让服务器来处理UI更新。这减少了客户端的开发工作量,使您的工作流程更加高效。

使用Stac的表单示例

让我们看看Stac的实际操作,通过构建一个简单的登录页面

服务器端的 JSON 定义

这里是服务器使用Stac JSON定义的登录界面:

    {  

      "type": "scaffold",  
      "backgroundColor": "#F4F6FA",  
      "appBar": {  
        "type": "appBar",  
        "backgroundColor": "#00FFFFFF",  
      },  
      "body": {  
        "type": "form",  
        "child": {  
          "type": "padding",  
          "padding": {"left": 24, "right": 24},  
          "child": {  
            "type": "column",  
            "crossAxisAlignment": "start",  
            "children": [  
              {  
                "type": "text",  
                "data": "登录账号",  
                "style": {"fontSize": 24, "fontWeight": "w800", "height": 1.3}  
              },  
              {"type": "sizedBox", "height": 24},  
              {  
                "type": "textFormField",  
                "id": "email",  
                "autovalidateMode": "onUserInteraction",  
                "validatorRules": [  
                  {"rule": "isEmail", "message": "请输入有效的邮箱地址"}  
                ],  
                "style": {"fontSize": 16, "fontWeight": "w400", "height": 1.5},  
                "decoration": {  
                  "hintText": "邮箱",  
                  "filled": true,  
                  "fillColor": "#FFFFFF",  
                  "border": {  
                    "type": "outlineInputBorder",  
                    "borderRadius": 8,  
                    "color": "#24151D29"  
                  }  
                }  
              },  
              {"type": "sizedBox", "height": 16},  
              {  
                "type": "textFormField",  
                "autovalidateMode": "onUserInteraction",  
                "validatorRules": [  
                  {"rule": "isPassword", "message": "请输入有效的密码:"}  
                ],  
                "obscureText": true,  
                "maxLines": 1,  
                "style": {"fontSize": 16, "fontWeight": "w400", "height": 1.5},  
                "decoration": {  
                  "hintText": "密码",  
                  "filled": true,  
                  "fillColor": "#FFFFFF",  
                  "border": {  
                    "type": "outlineInputBorder",  
                    "borderRadius": 8,  
                    "color": "#24151D29"  
                  }  
                }  
              },  
              {"type": "sizedBox", "height": 32},  
              {  
                "type": "filledButton",  
                "style": {  
                  "backgroundColor": "#151D29",  
                  "shape": {"borderRadius": 8}  
                },  
                "onPressed": {  
                  "actionType": "none",  
                },  
                "child": {  
                  "type": "padding",  
                  "padding": {"top": 14, "bottom": 14, "left": 16, "right": 16},  
                  "child": {  
                    "type": "row",  
                    "mainAxisAlignment": "spaceBetween",  
                    "children": [  
                      {"type": "text", "data": "继续"},  
                      {  
                        "type": "icon",  
                        "iconType": "material",  
                        "icon": "arrow_forward"  
                      }  
                    ]  
                  }  
                }  
              },  
              {"type": "sizedBox", "height": 16},  
              {  
                "type": "align",  
                "alignment": "center",  
                "child": {  
                  "type": "textButton",  
                  "onPressed": {  
                    "actionType": "none",  
                  },  
                  "child": {  
                    "type": "text",  
                    "data": "忘记密码了吗?",  
                    "style": {  
                      "fontSize": 15,  
                      "fontWeight": "w500",  
                      "color": "#4745B4"  
                    }  
                  }  
                }  
              },  
              {"type": "sizedBox", "height": 8},  
              {  
                "type": "align",  
                "alignment": "center",  
                "child": {  
                  "type": "text",  
                  "data": "没有账号?点击注册BettrDo",  
                  "style": {  
                    "fontSize": 15,  
                    "fontWeight": "w400",  
                    "color": "#000000"  
                  },  
                  "children": [  
                    {  
                      "data": "注册BettrDo",  
                      "style": {  
                        "fontSize": 15,  
                        "fontWeight": "w500",  
                        "color": "#4745B4"  
                      }  
                    }  
                  ]  
                }  
              }  
            ]  
          }  
        }  
      }  
    }
客户端: 实施

下面是如何使用 Stac.fromNetwork 方法来渲染由服务器定义的界面。

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

    void main() async {  
      await Stac.initialize();  
      runApp(const MyApp());  
    }  

    class MyApp extends StatelessWidget {  
      const MyApp({super.key});  

      @override  
      Widget build(BuildContext context) {  
        return MaterialApp(  
          title: 'Stac应用',  
          theme: ThemeData(),  
          home: Stac.fromNetwork(  
            request: Stac网络请求(  
              url: 'https://example.com/ui.json',  
            ),  
            context: context,  
          ),  
        );  
      }  
    }

只需几行代码和一个 JSON 定义,你就能得到一个由 Stac 驱动的动态登录界面。真的就这么简单!🚀

接下来会怎样?

准备好探索 Stac 了吗?前往我们的 GitHub 查看代码,了解 Stac 的实现细节,查阅我们的详细文档开始学习,探索 Stac 的功能,并使用 Stac Playground 实时操作动态 UI。这正是你需要的所有工具,用 Stac 快速构建出更智能、更出色的 app。

继续关注更多关于 Stac 的深度博客,我们将深入探讨高级功能、分享最佳实践和实际案例,帮助你全面挖掘其潜力!🌟

谢谢您的阅读 👋

希望你喜欢这篇文章。如果你有任何问题或建议,可以在下面留言告诉我。

你可以通过TwitterGithubLinkedIn关注我。你可以订阅我的邮件通讯,以获取我最新文章的邮件更新。

编码愉快……下次见啦,👋

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消