Flutter 发布 APP (Android and iOS)

Keep in memory.

For Android

准备好为Android准备的release版时, 需要执行一下步骤

检查 App Manifest

查看默认应用程序清单文件(位于<app dir>/android/app/src/main/中的AndroidManifest.xml文件),并验证这些值是否正确,特别是:

  • application: 编辑 application 标签, 这是应用的名称。

  • uses-permission: 如果您的应用程序代码不需要Internet访问,请删除android.permission.INTERNET权限。标准模板包含此标记是为了启用Flutter工具和正在运行的应用程序之间的通信。

查看构建配置

查看默认[Gradle 构建文件][gradlebuild]”build.gradle”,它位于<app dir>/android/app/,验证这些值是否正确,尤其是:

  • defaultConfig:

    • applicationId: 指定始终唯一的 (Application Id) appid

    • versionCode & versionName: 指定应用程序版本号和版本号字符串。

    • minSdkVersion & targetSdkVersion: 指定最低的API级别以及应用程序设计运行的API级别。

添加启动图标

当一个新的Flutter应用程序被创建时,它有一个默认的启动器图标。要自定义此图标:

  1. 查看(Android启动图标)[https://material.io/design/iconography/] 设计指南,然后创建图标。

  2. <app dir>/android/app/src/main/res/目录中,将图标文件放入使用配置限定符命名的文件夹中。默认mipmap-文件夹演示正确的命名约定。

  3. 在AndroidManifest.xml中,将application标记的android:icon属性更新为引用上一步中的图标(例如 <application android:icon="@mipmap/ic_launcher" …)。

  4. 要验证图标是否已被替换,请运行您的应用程序并检查应用图标

app签名

创建 keystore

如果您有现有keystore,请跳至下一步。如果没有,请通过在运行以下命令来创建一个:keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

注意:保持文件私密; 不要将它加入到公共源代码控制中。

注意: keytool可能不在你的系统路径中。它是Java JDK的一部分,它是作为Android Studio的一部分安装的。有关具体路径,请百度。

引用应用程序中的keystore

创建一个名为<app dir>/android/key.properties的文件,其中包含对密钥库的引用:

1
2
3
4
storePassword=<password from previous step>
keyPassword=<password from previous step>
keyAlias=key
storeFile=<location of the key store file, e.g. /Users/<user name>/key.jks>

注意: 保持文件私密; 不要将它加入公共源代码控制中

在gradle中配置签名

通过编辑<app dir>/android/app/build.gradle文件为您的应用配置签名

替换:

1
android {

为:

1
2
3
4
5
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

android {

替换:

1
2
3
4
5
6
7
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}

为:

1
2
3
4
5
6
7
8
9
10
11
12
13
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}

现在,您的应用的release版本将自动进行签名。

构建一个发布版(release)APK

使用命令行:

  1. cd <app dir> ( 为您的工程目录).
  2. 运行flutter build apk (flutter build 默认会包含 –release选项).
    打包好的发布APK位于<app dir>/build/app/outputs/apk/app-release.apk

在设备上安装发行版APK

按照以下步骤在已连接的Android设备上安装上一步中构建的APK

使用命令行:

  1. 用USB您的Android设备连接到您的电脑
  2. cd <app dir> .
  3. 运行 flutter install .

(注意: <>为需要替换的内容)

iOS

准备

在开始发布您的应用程序之前,请确保它符合Apple的App Review Guidelines.

为了将您的应用发布到App Store,您需要注册Apple开发者计划。您可以在Apple的Choosing a Membership中阅读更多关于各种会员选项的信息。

Debian添加用户并分配权限组

部分指令同样适用在 mac os, ubuntu 等.

如何添加用户

1
adduser dubhe

添加拥有超级用户权限的新用户, 但在 sudo 的时候会要求输密码

1
sudo adduser dubhe

如何查看用户所在组

1
2
3
4
groups dubhe

[Output]
dubhe: dubhe

如何 添加用户进入组

usermod, 为用户切换模式, 输入选择项 -aG (add group) 加上组名, 最后紧跟用户名

1
usermod -aG sudo dubhe

通过键入执行具有管理权限的命令, 使用命令前缀sudo ,会提示输入密码。 输入该命令发出用户的密码, 而不是 root 用户的密码.

删除用户

1
deluser dubhe

以具有 sudo 权限的其他非root用户身份登录, 可以改为键入:

1
sudo deluser dubhe

编辑 用户配置的sudo的特权

1
visudo

Css Flex 布局

display: flex
An introduction about layout by flexbox (called flex as a value in display property.)

Property of Parent elements (Flex container)

display

Obviously, in this topic, the display of the parent must be ‘flex’, also it can be an inline element – ‘inline-flex’

flex-direction

1
2
3
.container {
flex-direction: row | row-reverse | column | column-reverse;
}

This property describe the direction of this whole flexbox.

  • row (default): left to right in ltr; right to left in rtl
  • row-reverse: right to left in ltr; left to right in rtl
  • column: same as row but top to bottom
  • column-reverse: same as row-reverse but bottom to top

flex-wrap

1
2
3
.container{
flex-wrap: nowrap | wrap | wrap-reverse;
}

This property describe whether the flexbox will be in oneline or in multiple lines.

  • nowrap (default): all flex items will be on one line
  • wrap: flex items will wrap onto multiple lines, from top to bottom.
  • wrap-reverse: flex items will wrap onto multiple lines from bottom to top.

flex-flow

1
flex-flow: <‘flex-direction’> || <‘flex-wrap’>

This is a shorthand flex-direction and flex-wrap properties, which together define the flex container’s main and cross axes. Default is row nowrap.

justify-content

1
2
3
.container {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
  • flex-start (default): items are packed toward the start line
  • flex-end: items are packed toward to end line
  • center: items are centered along the line
  • space-between: items are evenly distributed in the line; first item is on the start line, last item on the end line
  • space-around: items are evenly distributed in the line with equal space around them. Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies.
  • space-evenly: items are distributed so that the spacing between any two items (and the space to the edges) is equal.

align-items

1
2
3
.item {
align-items: center;
}

5 values include:

  • flex-start: cross-start margin edge of the items is placed on the cross-start line
  • flex-end: cross-end margin edge of the items is placed on the cross-end line
  • center: items are centered in the cross-axis
  • baseline: items are aligned such as their baselines align
  • stretch (default): stretch to fill the container (still respect min-width/max-width)

Property align-content

1
2
3
.flex-row {
align-items: center;
}

5 values include:

  • flex-start: cross-start margin edge of the items is placed on the cross-start line
  • flex-end: cross-end margin edge of the items is placed on the cross-end line
  • center: items are centered in the cross-axis
  • baseline: items are aligned such as their baselines align
  • stretch (default): stretch to fill the container (still respect min-width/max-width)

新建与服务器的 Ssh 连接

ssh 的配置及使用

原理

(一)基础

1) 公钥:用于加密,存在于服务器

2) 私钥:用于解密,存在于客户机

(二)流程

1)客户端向服务器发出连接请求

2)服务器查看客户端公钥(~/.ssh/authorized_keys)该客户机(客户机标志:用户@Host)对应的公钥

3)服务器验证公钥合法,则产生一条随机数(challenge),用公钥加密发送给客户端

4)客户端用私钥解密回传服务器端。

5)随机数一致,认证通过。

本地新建 ssh key

创建指令 ssh-keygen, 之后定义名称和密码

1. 直接保存进入服务器

使用 ssh-copy-id 保存进入 authorized_keys

1
ssh-copy-id -i ~/.ssh/id_rsa.pub dubhe@<server-ipaddress>

连接检查或检查 authorized_keys 内是否有你的公钥

1
2
3
ssh dubhe@<server-ipaddress>
# 查看
cat authorized_keys

2. 先上传后保存

上传 ssh public key 至服务器

使用 ftp 或 其他工具

保存 pub key 至服务器的 authorize_keys

注意 authorized_keys 拼写

1
2
3
4
# 查看
cat authorized_keys
# 写入
cat <pub.key> authorized_keys

mac 新建 alias

1
2
3
4
5
6
7
8
9
10
# 1. 编辑或新建.bash_profile文件
vim ~/.bash_profile
# 2. 设置别名
alias <别名>='指令'
# eg
alias ll='ls -Alh'
# 设置 ssh 别名
alias to-server='ssh -i <serverkey-localaddress> dubhe@<server-ipaddress>'
# 3. 重载该配置文件
$ source .bash_profile

Typhoon Api - 基于 api.dubheee.cn 的 Api 说明文档

Typhoon System API

热带气旋生命史系统 api 文档

api 路径包括 /typhoon//tools/ 两个主要的分支目录, 其中前者属于数据接口, 用于获取台风数据, 根目录可访问接口文档, 后者包括一些简单的工具, 例如使用 /qrcode/<link> 可得到 link 的二维码, 扫描二维码能够直接访问该页面.

API

数据来源于中国气象局热带气旋资料中心.
最新数据至2017年, 数据文件提供下载。更新日期:2018年5月14日

强度标记, 以正点前2分钟至正点内的平均风速为准, 参见《热带气旋等级》国家标准(GB/T 19201-2006):

0-    弱于热带低压(TD), 或等级未知,
1-    热带低压(TD, 10.8-17.1m/s),
2-    热带风暴(TS,17.2-24.4 m/s),
3-    强热带风暴(STS, 24.5-32.6 m/s),
4-    台风(TY, 32.7-41.4 m/s),
5-    强台风(STY, 41.5-50.9 m/s),
6-    超强台风(SuperTY, ≥51.0 m/s),
9- 变性,第一个标记表示变性完成.

台风数据

台风年频数据

typhoon/ total
method : GET
请求所有台风的年数据列表, 返回 [{"year":"2017","count":"23"},...]

台风年数据

typhoon/ lists
method : GET
params: year

参数 year ,可根据年份查询该年所有台风列表,无参数时返回所有年份,以下为year=2017返回部分样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
{
"num": 201730,
"name": "天秤",
"englishname": "Tembin",
"startat": "2017-12-20T00:00:00",
"endat": "2017-12-26T06:00:00",
"year": 2017
},
{
"num": 201729,
"name": "启德",
"englishname": "Kai-Tak",
"startat": "2017-12-13T00:00:00",
"endat": "2017-12-22T18:00:00",
"year": 2017
}
]

台风路径点数据

typhoon/ points
method: GET
params: typhoonnumber
参数为台风编号 typhoonnumber, 请求单个台风的路径信息
例如points?typhoonnumber=199901返回如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[{
"name": "-",
"ename": "Iris",
"typhoonnumber": 199901,
"happenedat": "1999-02-16T06:00:00",
"typhoontime": "1999021606",
"latitude": 11.5,
"longitude": 132.9,
"intensity": 1.0,
"windspeed": 15.0,
"airpressure": 1002.0,
"ordinarywindspeed": 0.0,
"is_change": false,
"isdelete": false
},
{
"name": "-",
"ename": "Iris",
"typhoonnumber": 199901,
"happenedat": "1999-02-16T12:00:00",
"typhoontime": "1999021612",
"latitude": 11.5,
"longitude": 132.2,
"intensity": 1.0,
"windspeed": 15.0,
"airpressure": 1002.0,
"ordinarywindspeed": 0.0,
"is_change": false,
"isdelete": false
}]

台风生命史图点数据

typhoon/graphpoints
method: GET
params: typhoonnumber
参数为台风编号 typhoonnumber, 请求单个台风的路径信息
例如points?typhoonnumber=199901返回如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[
{
"name": "-",
"ename": "Iris",
"typhoonnumber": 199901,
"happenedat": "1999-02-16T06:00:00",
"intensity": 1.0,
"isdelete": false,
"is_change": false
},
{
"name": "-",
"ename": "Iris",
"typhoonnumber": 199901,
"happenedat": "1999-02-18T12:00:00",
"intensity": 0.0,
"isdelete": false,
"is_change": false
}
]

TOOLS

URLtoQRCODE

tools/qrcode/path:url
method: GET
params: url
参数为需要转换的地址, 地址需作 uricomponent 转码, 返回该地址的二维码
例如tools/qrcode/http%3A%2F%2Ftyphoon.dubheee.cn%2F%23返回如下:
二维码返回情况