Write the Code. Change the World.

11月 09

习惯了服务端调用接口(unipush1),没有使用过云函数的朋友,又对 unipush2 的文档没完全操作一遍。一般会觉得 unipush2 的服务端调用有些奇怪。其实,如果按照文档走下去,也会没事。

其实,unipush2 的服务端调用和传统的服务端调用接口一样的。只是这里是调用的 dcloud 的 url。把那个 url 当做是服务端要调用的接口就可以了。
那这个 url 又怎么来,就是通过对建立的云函数 url 化就可以了。这里,重点就是讲怎么建立云函数以及怎么将云函数 url 化,还有通过 postman 进行测试。

其实,通过这种方式,更自由简单。只要读 dcloud 的文档就可以了,完全不考虑个推,也不用去注册个推账号。

unipush2.0 官方文档

准备工作

如果已打包成功,在 dcloud 上推送证书也配置好了,并且通过 dcloud 的后台测试成功过推送。准备工作就不用看了。直接看最后的正题如何建云函数以及 url 化,还有调用。

这里以 ios 端为例,以手机端基座为例。(正式版就是直接打包和换个证书)

准备打包 app

1.1 - 配置 app 模块。

打开项目根目录下的 manifest.json 文件, 切换到 App模块配置, 按图这样勾选,保存。

1.2 打包基座。

点击顶部菜单, 发行->原生App-云打包,出现弹窗, 按上图这样配置,打包基座。会提示您打包成功或失败。肯定要成功哈。有了基座就方便干事了。

1.3 运行到基座。

将手机和 mac 连接好。点击顶部菜单,运行->运行到手机或模拟器->运行到iOS App基座,弹窗,确定直到提示成功,手机那边启动 app就好了。

1.4 在手机端打开 app,同意各种权限。

dcloud 后台配置证书

推送虽然用到个推,可用户不用管个推,dcloud 官方自己管就可以。

点击下边链接,进入到 dcloud 开发中心进行证书配置。一定要选择好对应的 app, 就是当前应用选择。

点击侧边栏,选择 应用信息,开始配置信息,iOS BundleId 配正确,关联服务空间选选好。

再点击侧边栏的 厂商推送设置,如上图所示,进行配置。

https://dev.dcloud.net.cn/pages/app/push2/thirdparty

dcloud 后台测试推送

获取 cid

        uni.getPushClientId({
            success: (res) => {
                let push_clientid = res.cid
                console.log('客户端推送标识:',push_clientid)
            },
            fail(err) {
                console.log(err)
            }
        });

如果前边的动作都正确,你应该会收到推送的。

到这里一定要保证能收到通知。到此,仅仅是使用 dcloud 的后台测试,不能用于正式项目场景。正式项目场景往往需要通过后端接口调用推送。比如有人支付了一个报名了一个活动。可以通过后端把这个推送信息发送到活动发布者那里,告诉他有人参加了活动,请及时处理。

新建云函数

1.1 创建云开发环境,关联云服务空间

鼠标放在项目名称上,右键选择 创建uniCloud云开发环境,选择 阿里云。选择什么云,和你在 dcloud 后台创建关联的云一样就可以了。先默认创建一个云开发环境。

1.2 创建云函数

1.3 配置和编写云函数

package.json

{
  "name": "unipush",
  "version": "1.0.0",
  "main": "index.js",
  "description": "消息推送",
  "extensions": {
    "uni-cloud-push": {}
  },
  "author": "vini123"
}

index.js

'use strict';

exports.main = async (event, context) => {
    let body = event.body;
    if (event.isBase64Encoded) {
        body = Buffer.from(body);
    }

    if(!body) {
        return { message: 'no body'};
    }

    const param = JSON.parse(body);

    // 云函数是通用的,和项目没有直接的关系。通过传递 appId,可以为多个项目进行推送
    const uniPush = uniCloud.getPushManager({
        appId: param.appId
    });

    return await uniPush.sendMessage({
        "push_clientid": param.push_clientid,
        "title": param.title,
        "content": param.content,
        "payload": param.payload,
        "force_notification": true,
        "request_id": param.request_id,
        "badge": param.badge
    });
};

云函数

uniPush.sendMessage 介绍

1.4 上传和运行云函数。因为该函数写了需要接受参数,不方便直接运行。如果想直接运行,将上边的参数直接写死。直接 send。鼠标右键上传并运行 就好。这里是动态的,仅仅上传部署就好了。

同名函数会相互覆盖。记得记得。所以这里 unipush 就要做一个通用的。(未关联云服务空间是不能上传的,先进行关联)

1.5 后台查看云函数

点击登录查看云函数

如果能看到上图这样的,表示你云函数已经好了。怕 dcloud 域名长不好记,可以绑定你自己备案过的域名。通过设置 CNAME 记录来映射。

配置自定义域名

1.6 函数 url 化说明

云函数->云函数管理 页面,点击页面底下的 云函数URL化 的编辑按钮,设置访问 path。

通过https://${云函数Url化域名}/${path}直接访问函数,其中${path}是配置的函数触发路径或其子路径。

https://${云函数Url化域名}/ 部分,你创建云空间的时候就有了。只是你如果自定义成自己的域名后,会变成你的域名。这些在云函数详情页面都会完全显示。我们只需要定义 path 部分。path 最好和函数名一致,这样比较好理解。比如叫 unipush, 就知道这个 url 是做推送用的。完整的 url 如:https://xxx.com/unipush 简单吧,自定义的域名短呀短,好记呀好记。

1.7 使用 postman 调用该函数(就是以 get 方式访问该 url,参数记得要带上。访问方式要注意 get 和 post 会有所不同)

postman 配置如上图所示。这里没有任何授权,也就是任何人都可以调用。注意保护好隐私。

手机端接受到推送效果如上图所示。

1.8 上边算是测试完成了。你可以在自己的服务端如 php、java、go等服务端去请求 url 调用。

这里是 php 的实例:

        $data = [
            'appId' => '__UNI__Axxxxx,
            'push_clientid' => 'fe6d8614ddcc42a30fc10xxxxxxx',
            'title' => '小区宝来电',
            'content' => '人生若只如初见,何事秋风悲画扇。',
            'payload' => ['text' => '体验一下吧'],
        ];

        curl('https://xxxx.com/unipush', json_encode($data), true, true);

        /**
         * @param string $url 请求网址
         * @param bool $params 请求参数
         * @param bool $post 请求方式,是否是post
         * @param bool $https 请求http协议,是否是https
         * @return bool|mixed
         */
        function curl($url, $params = false, $post = false, $https = false)
        {
            $httpInfo = array();
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36');
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            if ($post === true) {
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
                curl_setopt($ch, CURLOPT_URL, $url);
            } else {
                if ($params === false) {
                    curl_setopt($ch, CURLOPT_URL, $url);
                } else {
                    if (is_array($params)) {
                        $params = http_build_query($params);
                    }
                    curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
                }
            }

            if ($https === true) {
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在
            }
            $response = curl_exec($ch);
            if ($response === false) {
                Illuminate\Support\Facades\Log::error(sprintf('curl 错误。 url:%s, error:%s', $url, curl_error($ch)));
                return false;
            }
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
            curl_close($ch);
            return $response;
        }
11月 06

不想用 sftp,就自己装个 ftp。

阿里云这片文章就够了

vsftpd(very secure FTP daemon)是Linux下的一款小巧轻快、安全易用的FTP服务器软件。本教程介绍如何在Linux实例上安装并配置vsftpd。

https://help.aliyun.com/document_detail/182263.html

背景信息

FTP(File Transfer Protocol)是一种文件传输协议,基于客户端/服务器架构,支持以下两种工作模式:

  • 主动模式:客户端向FTP服务器发送端口信息,由服务器主动连接该端口。
  • 被动模式:FTP服务器开启并发送端口信息给客户端,由客户端连接该端口,服务器被动接受连接。

FTP支持以下三种认证模式:

  • 匿名用户模式:任何人无需密码验证就可以直接登录到FTP服务器。这种模式最不安全,一般只用来保存不重要的公开文件,不推荐在生产环境中使用。
  • 本地用户模式:通过Linux系统本地账号进行验证的模式,相较于匿名用户模式更安全。
  • 虚拟用户模式:FTP服务器的专有用户。虚拟用户只能访问Linux系统为其提供的FTP服务,而不能访问Linux系统的其它资源,进一步增强了FTP服务器的安全性。

    这里主要介绍被动模式下,使用本地用户访问FTP服务器的配置方法。

操作一波

1.1 安装

yum install  vsftpd

2.1 开启服务

systemctl start vsftpd

3.1 设置开机启动

  1. 先查看是否开机启动:
systemctl list-unit-files | grep vsftpd
  1. 我的系统显示这样:
systemctl list-unit-files | grep vsftpd
vsftpd.service                              disabled
vsftpd@.service                            indirect
vsftpd.target                               disabled

这里是未开通。

  1. 开启自启。
chkconfig vsftpd on
  1. 查看 ftp 服务监听的端口
netstat -antup | grep ftp

4.1 配置 vsftpd

为保证数据安全,本文主要介绍被动模式下,使用本地用户访问FTP服务器的配置方法。

# 创建用户 ftplin
adduser ftplin

# 给 ftplin 设置密码
passwd ftplin

# 创建一个供 ftp 使用的目录
mkdir /var/ftp/lin

# 创建一个测试文件
vim /var/ftp/lin/test.txt
# 填入 hello 保存退出

# 给 /var/ftp/lin 设置所有者
chown -R ftplin:ftplin /var/ftp/lin

再去修改 vsftpd.conf 配置文件:

vim /etc/vsftpd/vsftpd.conf

4.1 修改配置文件

vim /etc/vsftpd/vsftpd.conf

按照以下要求修改

注意 修改和添加配置文件内的信息时,请注意格式问题。例如,添加多余的空格会造成无法重启服务的结果。

#除下面提及的参数,其他参数保持默认值即可。

#修改下列参数的值:
#禁止匿名登录FTP服务器。
anonymous_enable=NO
#允许本地用户登录FTP服务器。
local_enable=YES
#监听IPv4 sockets。
listen=YES

#在行首添加#注释掉以下参数:
#关闭监听IPv6 sockets。
#listen_ipv6=YES

#在配置文件的末尾添加下列参数:
#设置本地用户登录后所在目录。
local_root=/var/ftp/test
#全部用户被限制在主目录。
chroot_local_user=YES
#启用例外用户名单。
chroot_list_enable=YES
#指定例外用户列表文件,列表中用户不被锁定在主目录。
chroot_list_file=/etc/vsftpd/chroot_list
#开启被动模式。
pasv_enable=YES
allow_writeable_chroot=YES
#本教程中为Linux实例的公网IP。
pasv_address=FTP服务器公网IP地址
#设置被动模式下,建立数据传输可使用的端口范围的最小值。
#建议您把端口范围设置在一段比较高的范围内,例如50000~50010,有助于提高访问FTP服务器的安全性。
pasv_min_port=port number
#设置被动模式下,建立数据传输可使用的端口范围的最大值。
pasv_max_port=port number

创建chroot_list文件,并在文件中写入例外用户名单。

# 输入例外用户名单。此名单中的用户不会被锁定在主目录,可以访问其他目录。及时没有例外用户,该文件也必须创建,内容为空。
# 个人建议该文件为空最好,不必去访问其他目录,世界一片安静多好呀。
vim /etc/vsftpd/chroot_list

重启服务

systemctl restart vsftpd.service

到此为止, ftp 的配置已经完了。但阿里云还得配置安全组。21 端口入方向必须打开以及上边配置的访问的最小到最大端口也要配置。

设置安全组

规则方向 授权策略 协议类型 端口范围 授权对象
入方向 允许 TCP 21/21 所有要访问FTP服务器的客户端公网IP地址,多个地址之间用逗号隔开。允许所有客户端访问时,授权对象为0.0.0.0/0。
入方向 允许 TCP pasv_min_port/pasv_max_port。例如:50000/50010 所有要访问FTP服务器的客户端公网IP地址,多个地址之间用逗号隔开。允许所有客户端访问时,授权对象为0.0.0.0/0。

可以测试了

使用 ftp 工具。比如 win 的 ftpx, mac 的 forklift 。输入公网 ip 地址,选择 ftp 连接方式(端口号不用管),填入用户名和密码。点击连接。是不是马上就好了,并进入到指定的目录了哈。

11月 06

处理 ** API getFileSystemManager is not yet implemented** 问题

wx.chooseImage({
      success: res => {
         let base64 = wx.getFileSystemManager().readFileSync(res.tempFilePaths[0], 'base64');
      }
 })

 wx.canvasToTempFilePath({
                    success: res => {
                        let base64 = wx.getFileSystemManager().readFileSync(res, 'base64');
                    }
});

对应到 uniapp,将 wx 换成 uni 即可。如:

# 该方法在微信小程序中可行,混编的 h5 不行,可通过条件编译处理
uni.getFileSystemManager().readFileSync(r, 'base64');

# 处理如下
            // 将网络图片转换成 base64 各不相同
            // #ifdef APP-PLUS
            uni.request({
                url: this.extra.topic.thumbnail,
                method: 'GET',
                responseType: "arraybuffer",
                success: res => {
                    const arrayBuffer = new Uint8Array(res.data); //先将本地图片路径转换成array类型
                    const base64Img = uni.arrayBufferToBase64(arrayBuffer);  //再转换成base64类型
                }
            });
            // #endif

            // #ifdef MP
            uni.getImageInfo({
                src: this.extra.topic.thumbnail,
                success: res => {
                    if (res.errMsg == 'getImageInfo:ok') {
                        const base64Img = uni.getFileSystemManager().readFileSync(res.path, 'base64');
                    }
                },
                fail: error => {
                    this.extra.topic = null;
                }
            });
            // #endif
11月 03

使用一个 url 链接就可以打开一个 app,是个多方便的事情。不过,得先安装该 app 啊。不过,肯定是蛮好的。

相关链接

apple 文档

uniapp 文档

操作一波

  1. 创建 app id 的时候,要将 Associated Domains 打钩。

  1. 服务器端准备 apple-app-site-association 文件。该文件就是文件名,不需要任何后缀,内容如下:
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "VQYDABC49G.pro.xiangrong.xiaoqubao",
                "paths": [ "/ulink/*"]
            }
        ]
    }
}

apps 就是空的,appID 的 VQYDABC49G 去开发账号中 Certificates, Identifiers & Profiles 的 Identifiers 中查看,就是 App ID Prefix。后半的 pro.xiangrong.xiaoqubao 就是 Bundle ID。

paths 自己定义。用于处理可以跳转到App的链接,支持通配符*,?以及NOT进行匹配,匹配的优先级是从左至右依次降低。 apple-app-site-association 放在根目录,paths 加个路劲方便和其他路径区分开来。如果该域名也有其他业务的话。

上边的内容你要修改的好好的。然后放在域名映射的根目录的 .well-known 文件夹下。然后通过 xxxx/.well-known/apple-app-site-association 能够访问到就可以。

当然,如果使用 nginx,可以直接在 nginx 的 .conf 中配置 location 也可以。

  1. 上边都配置好了。然后,在 app 程序端配置打包就好。这里是 uniapp 的搞法。打开配置文件 mainfest.json ,找到 App 常用其他设置,然后在关联域这里添加新项即可。比如添加 applinks:zeipan.com, 通过源码视图就可以看的到的。如:
                "capabilities" : {
                    "entitlements" : {
                        "com.apple.developer.associated-domains" : [ "applinks:zeipan.com" ]
                    }
                },
  1. 打包。如果是 uniapp,先打包基座。删除手机上的已有 app(如果之前打包过)。然后运行,运行到 App Ios 基座。

  2. 测试。上边的部分都准备好了,打开备忘录,输入link 地址。 比如: https://zeipan.com/ulink/?title=test。 保存,点击链接。如果上边都配置对了,这个时候就可以打开刚才安装的 app。

  3. 接受参数。 通过 https://www.html5plus.org/doc/zh_cn/runtime.html#plus.runtime.arguments 获取参数。有了参数,你就可以做想做的事情,比如跳转到某个页面,传递某个参数等等。

这里以接受参数,然后跳转到某个页面为例:

let params = null;
if(plus.runtime.arguments != ""){
    try{
        params = JSON.parse(plus.runtime.arguments);
    }catch(e){
        let arr = plus.runtime.arguments.split('?');
        params = {};
        if (arr.length == 2) {
            arr = arr[1].split('&');
            for(let str of arr) {
                let p = str.split('=');
                if (p.length == 2) {
                    params[p[0]] = decodeURIComponent(p[1]);
                }
            }
        }
    }

    let tabbars = ['views/home/index', 'views/message/index', 'pages/mine/index'];  
    if (params.page) {
        let isTab = false;
        for(let tabbar of tabbars) {
            if (params.page.indexOf(tabbar) >= 0) {
                isTab = true;
                break;
            }
        }

        if (isTab) {
            uni.switchTab({
                url: params.page
            });
        } else {
            uni.navigateTo({
                url: params.page
            });
        }
    }
}

注意对传递的 url 进行 encodeURIComponent 和 decodeURIComponent。

11月 02

https://www.xbsee.com/down/165774/ed2k.html

https://www.ysdq.org/play/232-1-0.html

https://www.zsych.net/detail/shushanqixiazhiziqingshuangjianyueyu.html

古老电视剧名单

《蜀山奇侠之紫青双剑》

《雪花神剑》

《江湖恩仇录》

《仙鹤神针》

《九阴真经》

《日月神剑》

《莲花争霸》

《蜀山奇侠之仙侣奇缘》

各种网站

https://www.pianhd.cc/

http://www.kuvun.co/

11月 02

通过各种方式方法将 app 上传到 app sotre connect 中,准备提交新版本,进行发布时,发布构建版本不不见了。这个时候肯定会很着急的。咋办咋办呢。有一个反馈也行啊,没有任何反馈就是一抹黑。网上说使用了某个权限,没有在 plist 中进行说明。说明了就好。这个是一方面,也不全面。

不灯下黑

登录进去 app store connect,然后选择你的app,点击上方的 TestFlight,在这里可以看见你上传的 app 信息。如果是在处理中,等等就好(这是一个反馈,免得一抹黑),如果准备提交。你就可以去构建版本了。

11月 02

判断手机上是否安装了常用的 app 是一个很必要的功能。比如你 ios 端,想做微信登录功能,就得先判断手机是否安装了微信。因为如果你不判断,直接显示微信按钮,如果用户手机根本没装微信,app 上架就会不成功。

https://ask.dcloud.net.cn/article/35621

https://ask.dcloud.net.cn/article/39182

调用 api

let pinfo = {
    pname: 'com.tencent.mm',
    action: 'weixin://'
}

let hasWeixin = plus.runtime.isApplicationExist(pinfo);

console.log(hasWeixin)

通过 URLscheme 信息,通过 plus.runtime.isApplicationExist 来判断。

常用的 app URLscheme信息

平台 pname action
微信 com.tencent.mm weixin://
QQ com.tencent.mobileqq mqq://
微博 com.sina.weibo sinaweibo://
淘宝 com.taobao.taobao taobao://
支付宝 com.eg.android.AlipayGphone alipay://
京东 com.jingdong.app.mall openApp.jdMobile://
高德地图 com.autonavi.minimap iosamap://
百度地图 com.baidu.BaiduMap baidumap://
优酷 com.youku.phone youku://
拼多多 com.xunmeng.pinduoduo pinduoduo://
小区宝 pro.xiangrong.xiaoqubao xiaoqubao://

哈哈,当然我们小区宝也有

拼多多 URLscheme

额外

# app 系统
let osName = plus.os.name;
console.log(osName);
# 系统名字 Android,iOS

自己的 app 设置 URLscheme

IOS 配置方法

Android 配置方法

https://uniapp.dcloud.net.cn/tutorial/app-ios-schemes.html#