【Flutter 手机 app 开发】

【前言】

就目前而言,由于之前从未接触过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: [
        _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 当中先行注册,然后再在运行时代码中写入申请动作。
全权限注册参照表





    CFBundleDevelopmentRegion
    en
    CFBundleExecutable
    $(EXECUTABLE_NAME)
    CFBundleIdentifier
    $(PRODUCT_BUNDLE_IDENTIFIER)
    CFBundleInfoDictionaryVersion
    6.0
    CFBundleName
    permission_handler_example
    CFBundlePackageType
    APPL
    CFBundleShortVersionString
    $(FLUTTER_BUILD_NAME)
    CFBundleSignature
    ????
    CFBundleVersion
    $(FLUTTER_BUILD_NUMBER)
    LSRequiresIPhoneOS
    
    UILaunchStoryboardName
    LaunchScreen
    UIMainStoryboardFile
    Main
    UISupportedInterfaceOrientations
    
        UIInterfaceOrientationPortrait
        UIInterfaceOrientationLandscapeLeft
        UIInterfaceOrientationLandscapeRight
    
    UISupportedInterfaceOrientations~ipad
    
        UIInterfaceOrientationPortrait
        UIInterfaceOrientationPortraitUpsideDown
        UIInterfaceOrientationLandscapeLeft
        UIInterfaceOrientationLandscapeRight
    
    UIViewControllerBasedStatusBarAppearance
    

    
    NSLocationWhenInUseUsageDescription
    Need location when in use
    NSLocationAlwaysAndWhenInUseUsageDescription
    Always and when in use!
    NSLocationUsageDescription
    Older devices need location.
    NSLocationAlwaysUsageDescription
    Can I have location always?

    
    NSAppleMusicUsageDescription
    Music!
    kTCCServiceMediaLibrary
    media

    
    NSCalendarsUsageDescription
    Calendars

    
    NSCameraUsageDescription
    camera

    
    NSContactsUsageDescription
    contacts

    
    NSMicrophoneUsageDescription
    microphone

    
    NSSpeechRecognitionUsageDescription
    speech

    
    NSMotionUsageDescription
    motion

    
    NSPhotoLibraryUsageDescription
    photos

    
    NSRemindersUsageDescription
    reminders



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

3.系统提示框调用

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

4.本地数据存储与调用

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

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

info.plist 里面直接添加






    NSAppTransportSecurity
    
        NSAllowsArbitraryLoads
        
    



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

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

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

你可能感兴趣的:(【Flutter 手机 app 开发】)