那个固执的少年回来了 《孤岛 App》这个系列已经停更了很久,这次全面升级,对的起给我star
的老铁们
介绍
APP 名称:《独 °》
客户端方案:flutter
服务端方案:Koa2
功能
写着完善着
- 我的
- 个人信息
- 头像修改
- 首页
- 列表页
- 发送图文、视频等
……
复制代码
前序准备
- 下文链接预警
- 长文预警
- 唠嗑方式不正经预警
- 错别字警告
当开始全面更新迭代的时候,没有产品
的思维是多么可怕的一件事,开发的过程中会同步更新系列文章,希望一块撩一撩flutter
当然了这些文章都是没有更新的
- Flutter 实战 从头撸一个「孤岛」APP(No.1、项目初始化、屏幕适配)
- Flutter 实战 从头撸一个「孤岛」APP(No.2、闪屏 Splash Page、引导页)
- Flutter 实战 从头撸一个「孤岛」APP(No.3、书单、搜索框、Dio 初探)
- Flutter 实战 从头撸一个「孤岛」APP(No.4、流行、点赞、动画)
分支变动
是这样的,咱们把之前持续更新的移动到lsolated_island_app
这个分支。想要翻看的可以自行
clone
《独》所有的开发现在
master
分支。
可能旧的文档地址找不到的情况,这个我后续更新一下
之前我的评论区
- 问:为啥 flutter 评论那么少
- 答:可能大家还不太了解
我觉得自己开发个小 app 也挺好玩的。
希望多多鼓励很关注,有不恰当的地方也欢迎指正。
友情建议:
最近一段时候由于公司需求,笔者在用 Vue 生态的 uniapp 技术栈来开发 app,总体体验是不太好的
不做什么横向对比,在正确使用 flutter 的前提下,flutter 开发的应用是相比于 uniapp 好很多的(这只是我个人看法)
个人感觉 flutter 的学习成本还是比较高的,如果公司想要通过这个技术来开发的话,可能需要有同事持续跟进 flutter 的生态发展,并定期分享给成员,因为 flutter 生态是越来越活跃,技术的更新迭代是相当的迅速,相关的第三方包插件今个能用。明天可能你就不知道咋回事了
flutter 只是一个简单的 UI(这里特别说一下并没有所谓的嵌套问题),但是其在安卓 IOS 上的渲染能力,动画能力是十分的惊人
最后简单说一下,企业项目十分花里胡哨的话,可能生态中并没有良好的解决方案,这就需要改一些现有的源码,什么和开发者沟通我该怎么实现,这也为什么企业选择 taro uniapp rn 等等
数据分析
- 为什么有的人说 flutter 凉了吗
- 有的人说 2020flutter 你跳槽张薪资必备
简单的数据说话
多终端解决方案 | 星星数 | |
---|---|---|
flutter | 88.3K | |
react-native | 85.5K | |
taro | 24.3K | |
uni-app | 19K |
虽然星星数
并不能说明什么,但在技术选型的时候,它还是一个十分重要的参考价值,笔者最近在做自己的全栈项目相信不久会出生吧
也只好通过以文字的时候,敦促自己,其实想想录视频也挺好的
慢慢来吧
BIOS 开启
由于简单配了台主机flutter
的运行需要 主机开启BIOS
模式
- 开机快速按
f12
或者DEL
也就是删除键 进入 BIOS(不同的电脑型号是不尽相同的) - 先不切换语言模式(一般情况下默认是 english)点击 Advanced Mode(F7)进入高级选项。
- 点击 Advanced,然后点 CPU Configuration。
- 下拉菜单找到 Intel Virtualization Technology,在其子菜单下把选项改成 Enabled。
- 按 F10 保存退出,开启成功。
- 这样一般就可以成功重启了
至于想我这样,多快的手速都进不去BIOS
的人,那可能需要简单的拆一下显卡
然后再简单的卸载一下主板的电池
乱七八糟的
唠嗑,好像跟
flutter
并没有什么关系,不过
在我们借用Asd
开启一个虚拟机设备调试的时候,可能会遇到一个问题,这就需要主机设备开启虚拟
一般情况下默认是不开启的。我是偏前端开发者,当然了看到这篇文章的你如果没在开发app
也不要走,因为技术就是金钱
flutter_du 初始化
准备
-
图片素材 登录页的背景图 免费图库相片 中文 台
assets: - lib/images/login_bg1.jpeg - lib/images/login_bg2.jpeg - lib/images/login_bg3.jpeg - lib/images/login_bg4.jpeg 复制代码
-
状态管理:全局状态管理方案(这一点在实际的开发中也是十分必要的)
-
插件:Flutter Provider Snippets vscode 插件 类和方法的集合 也规范化
provider
的书写
可以参考阅读一下我之前的分享 Flutter 状态管理一锅端:第一章 Provider ,这篇简单的介绍了如何在一个项目中管理数据,当然了即使是项目很简单,统一的管理数据可以尽可能的方便后期的维护,视图UI层与数据状态层分离
实现效果
实现的效果是底部轮播图,全屏的滑动
,由于这个效果图,我搞的gif
有点大7,8M
,放这个图片吧
目录结构
完全新建一个新的flutter项目
删除 main.dart 中的文件先,保留一个整洁的开始,它暂时是这样的
├─lib
│ ├─pages
│ │ └─login
│ └─provider
└─test
复制代码
provider
首先先实现provider
登录的状态管理,其中主要就是运用到的动画
相关的内容。动画相关的内容推荐阅读
那么刚开始我们就直接使用provider
是的,渐进式开发,遇到问题,解决问题。开发的过程中,我们可以自己写包然后上传到 flutter pub
- provider V4.04 这里最好可以直接 dev,也有中文网站
基本结构
import 'package:flutter/material.dart';
class LoginProvider extends State<StatefulWidget>
with ChangeNotifier, TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return null;
}
}
复制代码
状态 init
所谓的状态 init ,就是我们逻辑部分所用得到的初始化的数据,一般是空的 list 或者字符串等
Animation<double> bgAnimation; // 动画的
AnimationController bgController; // 控制器 文本输入同样有控制器
复制代码
double mainPicOp = 1; // 透明度
double otherPicOp = 0; // 透明度
复制代码
List<String> imgsList; // 背景图轮播的素材列表
imgsList = List<String>(); // 初始化
imgsList.add('lib/images/login_bg1.jpeg');
imgsList.add('lib/images/login_bg2.jpeg');
imgsList.add('lib/images/login_bg3.jpeg');
imgsList.add('lib/images/login_bg4.jpeg');
复制代码
int mainPicIndex = 0; // 当前正在显示的图片编号
int otherPicIndex = 1; // 备胎是1
复制代码
定时器
需要我们初始化定时器,让图片的透明度切换
Timer dingShiQi; // 定时器
dingShiQi = Timer.periodic(Duration(seconds: 2), (cb) {
bgController.forward(from: 0);
});
复制代码
主要逻辑
if (state == AnimationStatus.completed) {
mainPicIndex = mainPicIndex + 1;
otherPicIndex = otherPicIndex + 1;
if (mainPicIndex == imgsList.length) {
mainPicIndex = 0;
}
if (otherPicIndex == imgsList.length) {
otherPicIndex = 0;
}
mainPicOp = 1.0;
otherPicOp = 0.0;
notifyListeners();
}
复制代码
该释放的释放,该取消的取消
void dispose() {
dingShiQi.cancel();
bgController.dispose();
super.dispose();
}
复制代码
ui 布局
使用 provider
拿到provider
这样我们在无状态的组件中同样可以来取自如的使用数据
LoginProvider provider = Provider.of<LoginProvider>(context);
复制代码
核心代码
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => LoginProvider()),
],
child: Consumer<LoginProvider>(
builder: (context, counter, _) {
return MaterialApp(home: LoginPage());
},
),
);
}
复制代码
上边分享的代码是十分有必要的,因为provider
有个一次大的更新就是废除了build
然后改成了create
- MultiProvider 这是在需要多个
provider
- Consumer 相当于是监听订阅的变化
错误解决
其实在开发的过程中,有错误是十分正常的,也是十分常见的,尤其是在flutter
的开发中。更是一些莫名奇妙的问题,
- 不像 web 端有
console.log
console.table
等等直接可以在控制台打印输出
方案
- 一种有效的方案是世界
flutter run
,不要慌,不要怕 在 flutter 的开发中控制台一大大大大长串的错误很是常见
主要就是参考关键字
常见的关键字 然后出门google
也可以推门 Flutter 实际项目开发中踩坑大合集(持续更新..)
- 还有一种方案是 ,利用编辑器的调试工具
像这种一上来就是什么堆栈溢出
不过一般情况下,就是咱们的程序写的有问题
小结
本篇章的上半段呢便是对客户端项目的初始化,其中使用到了动画
这也是 flutter ui 中的核心力量,优雅的渲染能力;还有就是provider
在闲鱼的fish redux
等等等等一系列的状态管理实践中,当然了,使用哪个都行,但我觉得provider
不错。(前提是在用对的情况下)
实现模块
主要是登录页的一个背景图,透明度的切换
,并没有什么实质的内容。
预览
再更新的话,便是,客户端登录,然后请求到公网的数据,至于接口是什么,我想可以继续往下翻一番,感觉文章很随意的话,也请随意的分享
一下,请注明,来源
Koa2 初始化
后端的服务选型 ,最初有几种方案
- node 原生开撸 (这个主要是写的太啰嗦)
- Express Node 的一个框架(早期的)这个也行
- Koa2 现在一般都更新到第二代了,V2.11.0
- eggjs 这个企业级约定俗称也还不错(在笔者的其他项目用了,这个 flutter 就不用了)
- Nestjs 这个同步接口文档十分方便(属于尝鲜玩法,也在笔者的其他项目用了,那就也先不用在这儿)
所以这个就先用大名鼎鼎的Koa2
先来说说我对 koa2 的理解
- 洋葱模型,兜一圈又回来
- 异步编程 可以说 koa2 很好实践 js 异步编程理念
- 可定制化,根据习惯随意开发,拓展性强
项目目录
├─app
│ └─api
│ └─v1 // RESTful API 接口规范 v1 版本
├─core // 核心的代码
└─test
复制代码
开发依赖
在前端的项目中,package.json
一般这个就是管理包文件的,那在我们的flutter
项目中使用pubspec.yaml
文件是一样的,差不多
"dependencies": {
"koa": "^2.11.0", // 这个是项目依赖的koa 虽然名字还是koa但她已经是2代了
"koa-router": "^8.0.8", // 这个是路由跳转的
"require-directory": "^2.1.1" // 这个等会再说
}
复制代码
当然了这只是项目的初始化,后续更新会在此基础上,所以还是强烈建议看一下的。也可以收藏,没事的时候翻出来看看
入口文件
目前还是用js
来开发,如果对ts
感兴趣也可以推门
const Koa = require("koa");
const app = new Koa();
const Init = require("./core/init");
Init.entrance(app);
app.listen(3000);
复制代码
在这里我们新建了一个类
主要就是初始化应用的,这一点在 Nuxt
和 Next
等等的框架中都有核心的体现,包括在egg js
中 ,
- 导入 koa require("koa");
- 实例化 new Koa();
- 引入核心代码 require('./core/init')
- 传入 app Init.entrance(app)
- 监听端口 3000
还有一点十分重要就是在node
环境中模块化的规范不同于es6
的import
至于模块化规范,自行右转google
应用初始化类
// 初始化加载路由
const requireDirectory = require("require-directory");
const Router = require("koa-router");
class Init {
// 入口方法
static entrance(app) {
Init.app = app;
Init.initRoute();
}
// 路由导入初始化
static initRoute() {
requireDirectory(module, "../app/api", { visit: visitor });
function visitor(obj) {
if (obj instanceof Router) {
Init.app.use(obj.routes());
}
}
}
}
module.exports = Init;
复制代码
在这个文件中,我们引入了上文提及的require-directory
- 左转 批量导入相关文件
var requireDirectory = require('require-directory'),
visitor = function(obj) {
return obj(new Date());
},
hash = requireDirectory(module, {visit: visitor});
复制代码
意识是说我们可以导入文件,那么我们要做的就是自动化注入路由文件
-
user.js
// 个人中心v1-api const Router = require("koa-router"); const router = new Router(); router.get(`/api/v1/user`, (ctx, next) => { ctx.body = { code: 0 }; }); module.exports = router; 复制代码
我们整体遵循RESTful API
风格 api 不得不思考一个问题,关于后端接口迭代的问题,这也是为什么我们调用的接口会有v1
v2
版本前缀,这对于规范化开发十分重要。所以我们把路由文件这样安排
- app
- v1
- home.js
- v2
- v3
……
复制代码
启动后台服务
npm i // 没有几个包下起来很快
npm i -g nodemon // 自动监听文件变化,这在node开发过程中十分重要
复制代码
nodemon app.js
复制代码
直接在浏览器输入:
当看到接口返回的信息就说明后台的基本服务已经启动了,但是这还远远不够,远远的不够
{
"code": 0,
"data": {
"nickName": "yayxs",
"fav": [
{
"id": 1,
"type": "writing"
}
]
},
"msg": "获取用户信息成功"
}
复制代码
- 一、这是我们自己的本地服务,当写了十分炫酷的服务,显然是不便分享到他人的
- 二、这也还是我们自己的写的测试的 json 数据,并没有连接数据库
顺便先说一下,这个项目咱们用MySql
,感兴趣的话,你也可以推门 Node | 自我爬虫掘金专栏文章
服务器部署
核能预警
一提到服务器相关的知识
不要慌,我们一步步来实现公网IP
部署node 服务
目标
目标一:掌握 pm2 部署 node JS 服务 进行守护,进程
目标二:掌握基本的 nginx 反向代理
目标三:暂时拜别本地服务
效果
当我们在任何一台有网的电脑上地址栏输入 http://62.234.111.140/api/v1/user
,便会成功的返回我们所写接口返回的数据
云服务器准备
为什么说第一步要准备云服务器,因为哪怕你用原生html
或者说什什么的ssr渲染框架
或者说jQ
等等吧,哪怕是之前读书做的告白网站
你总得放在公网上吧,不然总不能把女孩子拉到自己的家里,然后npm run start
等等,你看你看………………
- X里云
- X讯云
- X为云
所以还是国内的BATH
等等这几家的,都差不多真的不骗你
问:什么是云服务器?什么是域名解析?什么是部署?怎么反向代理?那你能帮帮我吗??
答:你玩游戏的是啥 ,电脑,云服务器就是电脑(当然了在这里是不正确的也不是很准确的)
虽然我没有那么浪漫和骚,但是我有云服务器 还是包年的 公网 IP http://62.234.111.140/
希望大佬们不要对我做坏事情,跪拜
连接远程服务器
输入用户名密码连接就行了
这样就可以了,我发现真的是 废话好多啊 具体的细节,如果大家有什么疑问,可以再评论区留言,能力所及,会回复的。首先上来的时候要安装几个东西npm i -g node // 全局安装最新版的node环境
npm i -g pm2 // 全局安装线程管理
// 等等等等
复制代码
一切的环境准备好之后,就需要同步一下咱们的服务端代码到云服务器
这一点同样十分的重要,不然就没得进行了。
依赖三方服务器
总得有个同步的服务器,我们选择github
服务器,这样在云服务也好,还是咱们的本地电脑,代码最起码丢不了
我是放在了home
文件夹下
那就装依赖呗,老套路
cd /home/flutter-koa2-du/koa2-server
npm i
复制代码
趁着也安装一下nodemon
吧 答应我安装下好吗npm-nodemon
虽然说我们也是在本地开发然后同步到云服务器,云服务器的代码一般不会怎么变动,
启动项目
不要慌,解决问题
- 问题原因:主要是在同一环境 3000 这个端口已经被占用
- 解决问题:那就关闭 3000 进程
这个时候我们就要引入PM2
纯纯的大写的高调的pm2
Pm2 应用
首先来看下pm2
干些什么
- 内建负载均衡(使⽤ Node cluster 集群模块、⼦进程,可以参考朴灵的《深⼊浅出 node.js》⼀书 第九章)
- 线程守护,keep alive
- 0 秒停机重载,维护升级的时候不需要停机.
- 现在 Linux (stable) & MacOSx (stable) & Windows (stable).
- 多平台⽀持
- 停⽌不稳定的进程(避免⽆限循环)
- 控制台检测 id.keymetrics.io/api/oauth/l…
- 提供 HTTP API
可能现在这样说,也没设好理解的,是有一个这样的场景,云服务器的环境可不像我们本地的电脑,即开发环境(dev),一旦上线,会有各种复杂的问题出现,导致程序崩掉。不能够为我们提供服务
配置
npm install -g pm2
pm2 start app.js --watch -i 2
// watch 监听⽂件变化
// -i 启动多少个实例
pm2 stop all
pm2 list
pm2 start app.js -i max # 根据机器CPU核数,开启对应数⽬的进程
复制代码
这只是简单的配置,详细的玩法可以自行右转google
也可以下翻参阅文章关于pm2
的分享,当然了还是要滑上来的
pm2 list
我们可以通过pm2 list
查看进程启动情况,显然我们的项目已经在云服务器的3000
端口启动了,那么这个时候我们把进程stop all
停掉
pm2 stop all
我们通过命令先听到 3000 端口
pm2 优雅启动 node 进程服务
pm2 start app.js -i max -n node-koa-pm2
复制代码
详细的含义自行google
, ok 到这里应该就没什么问题了
curl 自行访问测试
curl http://127.0.0.1:3000/api/v1/user
复制代码
Nginx 反向代理
是这样的,我们考虑一下,接口访问的时候怎么才优雅,也不知道端口是 3000 啊,所以需要一个代理服务器
- 正向代理 :*******
- 反向代理:像这种就是反向代理,具体右转
google
安装
直接在云服务器通过yum
就可以了我觉得
yum install nginx
-----
apt update
apt install nginx
复制代码
然后怎么办呢,触及到我的知识盲区了,还是不要慌,遇到问题解决问题。敢于试错吧
nginx -v
查看当前云服务安装的nginx
版本
nginx -t
查看配置,这很重要,因为它会定位到nginx的主要配置所在的位置
,不同的安装方式所在的位置是不同的以下是笔者的
nginx: the configuration file /www/server/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /www/server/nginx/conf/nginx.conf test is successful
复制代码
cat nginx.conf
查看nginx
主要的配置文件,
…………………………
server
{
listen 888;
server_name phpmyadmin;
index index.html index.htm index.php;
root /www/server/phpmyadmin;
#error_page 404 /404.html;
include enable-php.conf;
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 12h;
}
location ~ /\.
{
deny all;
}
access_log /www/wwwlogs/access.log;
}
include /www/server/panel/vhost/nginx/*.conf;
}
复制代码
主要的要看重这句话include /www/server/panel/vhost/nginx/*.conf;
意思是说会引入后缀名.conf
的文件作为配置的一部分,所以当我们新增配置的时候,文件名要是.conf
这样 nginx 会导入并作为配置
这时候我们只需要新建一个**.conf
的文件就可,添加如下的配置
server {
listen 80;
server_name localhost;
location /api {
proxy_pass http://127.0.0.1:3000;
}
}
复制代码
我们新增的nginx
配置并没有包括
- 静态路由的配置
- 等等
重启 nginx
nginx -s reload
复制代码
没什么错误的话,应该就可以了, 这个时候验证一下自己的成果
{
"code": 0,
"data": {
"nickName": "yayxs",
"fav": [
{
"id": 1,
"type": "writing"
}
]
},
"msg": "获取用户信息成功"
}
复制代码
一个简单的get
请求旧简单的部署到服务器上
了
构建高可用的 node 环境
在干撸node
的时候,如何当进程抛出错误的时候。构建高可用的 node 是十分有必要的如下的代码可参考阅读,方便理解在服务端的环境下为什么需要 PM2 来管理进程、
- app.js
// app.js
// 引入koa
const Koa = require("koa");
// 创建⼀个Koa对象表示web app本身:
const app = new Koa();
// 对于任何请求,app将调⽤该异步函数处理请求:
app.use(async (ctx, next) => {
// 随机产⽣错误
Math.random() > 0.9 ? yayxs() : "2";
await next();
ctx.response.type = "text/html";
ctx.response.body = "<h1>success</h1>";
});
if (!module.parent) {
app.listen(3000);
console.log("app started at port 3000...");
} else {
module.exports = app;
}
复制代码
- test.js
// test.js
var http = require("http");
setInterval(async () => {
try {
await http.get("http://localhost:3000");
} catch (error) {}
}, 1000);
复制代码
- cluster.js
var cluster = require("cluster");
var os = require("os"); // 获取CPU 的数量
var numCPUs = os.cpus().length;
var process = require("process");
console.log("numCPUs:", numCPUs);
var workers = {};
if (cluster.isMaster) {
// 主进程分⽀
cluster.on("death", function(worker) {
// 当⼀个⼯作进程结束时,重启⼯作进程 delete workers[worker.pid];
worker = cluster.fork();
workers[worker.pid] = worker;
});
// 初始开启与CPU 数量相同的⼯作进程
for (var i = 0; i < numCPUs; i++) {
var worker = cluster.fork();
workers[worker.pid] = worker;
}
} else {
// ⼯作进程分⽀,启动服务器
var app = require("./app");
app.use(async (ctx, next) => {
console.log("worker" + cluster.worker.id + ",PID:" + process.pid);
next();
});
app.listen(3000);
}
// 当主进程被终⽌时,关闭所有⼯作进程
process.on("SIGTERM", function() {
for (var pid in workers) {
process.kill(pid);
}
process.exit(0);
});
复制代码
其他
近期感想
这一段的时间,上下班的时间一直在想产品
的相关的问题,才知道设计一个东西是多么的难,思维很混乱,这也是为什么这么久没更新(当初说好的一周一更呢)。
- 刚开始可能是面向自己,孤独的自己
- 接着可能会面向 B 端用户
- 大众的 C 端产品
每个人的思路,每个人的共享对于产品的诞生是多么的重要
- 哪怕一个实习生
- 哪怕一个刚开始企业开发的小生
- 哪怕一个宏观架构的大佬
都一样的,唯一不同的是工资
不一样的,当个爱好,没事分享分享
总结
这篇文章包含了两个大的方向flutter
与 node
- 如何重新出发,构思一个简答的跨端 app ,登录页
- 如何从 0 开始搭建一个简单的 node 后台服务,实现前端人的后端梦
- 如何入门了解
nginx
等服务端运维相关的知识,即使皮毛
求求
感觉有意思的也希望一切探讨。完整项目的 github 仓库地址独 °,真的希望能给个stat
这也是为什么我重新构思继续开发。
行文思路
参考阅读
- node 服务开发和服务器部署
- pm2---node 进程管理工具
- 开课吧全栈系列 12 期关于 node 相关分享
- B 站 马有发 发哥的 flutter 相关分享
来源:oschina
链接:https://my.oschina.net/u/4356296/blog/3207525