美文网首页rtzl
【Flutter 手机 app 开发】

【Flutter 手机 app 开发】

作者: zbcy0012 | 来源:发表于2020-07-26 10:15 被阅读0次

【前言】

就目前而言,由于之前从未接触过iOS开发工作,目前尚处于摸索过程中,一切工作成果以初步实现为最基准。
本文记载我研究如何使用 flutter 的过程,以 iOS 端为基础端,以及遇到的一些问题。

==================

一、本机调试运行

2020-12-28 起改为 flutter 框架。
现已成功上传至 testFlight

【研发行动步骤】

  • 找一个适合的 coding 编辑器
    vs code for mac

  • 真机调试
    (need registered device)
    flutter run

  • 了解代码结构、代码拆分

  • 创建一般页面

  • 添加页面交互
    就是特定可交互组件的特定属性值的设定

  • 路由实现:
    还是静态路由香

1.一般前进导向

 Navigator.of(context).push(new MaterialPageRoute(builder:(context){...}))

2.带参数前进导向
就像是props一样直接往方法的括号里面放,但是要注意强类型语言的参数定义与传递跟js略有不同。
方式一:

// 传参
Navigator.of(context)
        .pushNamed('/navigation2', arguments: {"start": start, "end": end});
// 接收参数
var obj = ModalRoute.of(context).settings.arguments;

3. 后退
由push构成的一般前进动作,appBar 部分会自带后退按钮,无需自定义
4.带参数后退(或者带参数伪后退)
但是只能带一个参数回来
5.不可逆前进(如登陆后、若不注销账户则不再能退到登陆页)

//从登录到主页
Navigator.of(context).pushReplacementNamed('/home');

//一般前进
Navigator.of(context).pushNamed("/page1");

// 退出登录
while (Navigator.of(context).canPop()) {
  Navigator.of(context).pop();
}
Navigator.of(context).pushReplacementNamed("/login");

6.底部菜单式目录
直接在 scaffold 的 bottomNavigationBar 接口处使用 BottomNavigationBar 组件


  • 组件拆分:props传递与state管理
class TopBar extends StatelessWidget with PreferredSizeWidget {

  /**********************关键代码**********************/
  final title;
  TopBar({@required this.title});
  /**********************关键代码**********************/

  @override
  Widget build(BuildContext context) {
    return AppBar(title: Text('${this.title}'));
  }

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

外部调用

TopBar(title: 'HomePage Title'),
  • 基本样式掌控
    ✓1.沉浸式状态栏
    好像 ios app 默认都是沉浸式无需特殊设置,而网上大部分沉浸式状态栏都是在针对安卓 app。
    ✓2.自定义顶部条高度、颜色、字体;后退按键颜色
    ✓3.自定义底部条高度、颜色、字体

  • 创建外接式html
    简单粗暴,没有问题。
    h5 与 flutter 的交互实现:
    h5 => flutter:
    理论:在 flutter 端注册 javascriptChannels ,然后监听特定 name 的回传再进行后续动作。
    flutter 端:

  // 创建 JavascriptChannel
JavascriptChannel _toastJsChannel(BuildContext context) => JavascriptChannel(
      name: 'show_flutter_toast',
      onMessageReceived: (JavascriptMessage message) {
        print("get message from JS, message is: ${message.message}");
       // _webViewController.evaluateJavascript('zbchell("rtzl hasaki")');
      });

  @override
  Widget build(BuildContext context) {
    return WebView(
      ...,
      javascriptChannels: <JavascriptChannel>[
        _toastJsChannel(context),
      ].toSet(),
    );
  }

JS 端:

if(window.show_flutter_toast)
  show_flutter_toast.postMessage(`someString`)

flutter => h5
理论:flutter 通过 webviewcontroller 的 evaluateJavascript 方法调起 web 端 window 名下的方法。
JS端:

// 注册可以被调起的函数
window.zbchell = function (text) {
  ...,
  // setState
  this.setState({
    ...  // if u need
  })
}

注意不要使用箭头函数声明,以免之后绑定 this 失败,除非你的这个方法当中并不需要使用特殊指向的 this。

flutter 端:

  // 创建 JavascriptChannel
  JavascriptChannel _toastJsChannel(BuildContext context) => JavascriptChannel(
      name: 'show_flutter_toast',
      onMessageReceived: (JavascriptMessage message) {
        print("get message from JS, message is: ${message.message}");
        // 执行!!
        _webViewController.evaluateJavascript('zbchell("rtzl hasaki")');
      });
  • 创建内嵌式html文件与互相通信、内嵌html且外接css
    1.本地html文件读取运行
    2.本地html与 flutter 互相通信
    暂且免谈

症状:只能渲染本地的 html 文件,而无法加载 html 对 css 和 js 文件的引入
解决思路:
a.整个网页全部外接(部署在服务器上)
结论:简单粗暴,没有问题。
b.将所有文件打包至一个 .html 文件当中(付诸实践...)
结论:大图片等外部资源只要有引入,则一概无法衔接(暂时废弃)


至此,套壳应用已理论上可实现。


接下来的内容为边做边研究
目的:开发一款包含截至目前所有组件的 rtzl 的开发者 app。

〇、ALL OUT

1.修改 app 桌面图标:

有很多尺寸的图标(共15个不同命名的图标,尺寸可能有重叠部分),由 Contents.json 管理配置。

2.修改 app 桌面名称:

到 info.plist 当中修改。(虽然 flutter 号称跨平台框架,然而这部分 ios android 各自为政)。

3.设置 app 启动画面:

有几个尺寸命名,由 Contents.json 管理配置。不过这里也可以使 app 无视屏幕尺寸大小,统一使用一个图片。

一、核心技术代码

1.等价于 React 的 componentDidMount 的方法:

需要使用 statefulWidgets 来实现

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => _didMount(context));
  }

// 这里就是自定义的在 build 被调用完之后触发动作的地方
  _didMount(context) {
    Navigator.of(context).pushNamed("/choose-entry");
  }

2.权限申请

正规的 app 操作统一为在使用时询问用户是否予以功能使用授权,特殊页面用到时动态申请或者 app 第一次运行时申请。
iOS 与 Android 是一样的步骤:
Android 需要在 AndroidMenifest.xml 文件当中声明,然后再在运行时代码中写入申请动作;
iOS 则是在 info.plist 当中先行注册,然后再在运行时代码中写入申请动作。
全权限注册参照表

<?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>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>permission_handler_example</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>$(FLUTTER_BUILD_NAME)</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>$(FLUTTER_BUILD_NUMBER)</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>

    <!-- Permission options for the `location` group -->
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Need location when in use</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>Always and when in use!</string>
    <key>NSLocationUsageDescription</key>
    <string>Older devices need location.</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Can I have location always?</string>

    <!-- Permission options for the `mediaLibrary` group -->
    <key>NSAppleMusicUsageDescription</key>
    <string>Music!</string>
    <key>kTCCServiceMediaLibrary</key>
    <string>media</string>

    <!-- Permission options for the `calendar` group -->
    <key>NSCalendarsUsageDescription</key>
    <string>Calendars</string>

    <!-- Permission options for the `camera` group -->
    <key>NSCameraUsageDescription</key>
    <string>camera</string>

    <!-- Permission options for the `contacts` group -->
    <key>NSContactsUsageDescription</key>
    <string>contacts</string>

    <!-- Permission options for the `microphone` group -->
    <key>NSMicrophoneUsageDescription</key>
    <string>microphone</string>

    <!-- Permission options for the `speech` group -->
    <key>NSSpeechRecognitionUsageDescription</key>
    <string>speech</string>

    <!-- Permission options for the `sensors` group -->
    <key>NSMotionUsageDescription</key>
    <string>motion</string>

    <!-- Permission options for the `photos` group -->
    <key>NSPhotoLibraryUsageDescription</key>
    <string>photos</string>

    <!-- Permission options for the `reminder` group -->
    <key>NSRemindersUsageDescription</key>
    <string>reminders</string>

</dict>
</plist>

权限申请(.request())时,都是隐式检测如果已授权,则什么都不发生,如果未授权才会提示申请权限,当你需要在有/无权限时分别有其他动作的时候才会用得到权限状态判定。

3.系统提示框调用

目前没有任何方法可以调用出原生的提示框,只能使用flutter提供的Widgets实现。初步分析可能涉及到 flutter 调用原生接口的过程。

4.本地数据存储与调用

任务一:开发一个网站显示页的前置配置页(用于配置访问地址)

5.使iOS应用允许http不安全通讯请求

info.plist 里面直接添加


<?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>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
</dict>
</plist>

5.在Mac上部署flutter android开发环境时,中文未提到的细节

  • 如果报错,可能是使用的java版本有问题,找了好久才知道是该使用 java 8 ,不要搞错了版本。
  • 设置java环境变量,随便找个位置
export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_241`

注意尾部的版本号,可能与文中有所不同

相关文章

网友评论

    本文标题:【Flutter 手机 app 开发】

    本文链接:https://www.haomeiwen.com/subject/vwfwlktx.html