HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

uniapp开发的网页SEO优化方案-适用于uni-app开发的web站点, uniapp手机端网页适配优化

优化 SEO uniapp

基于nginx服务器优化的方案, 适用于 uniapp开发的网站, 可适用于老项目

由于官网的插件暂时不支持老的项目,所以使用这种方法
本教程亲测可用, 以及上线的项目网址: http://al.jn1tea.com/
打开调试工具, 手机模式, ctrl + u 可以查看每个页面的 seo内容**

教程内容有点长, 请耐心看完

1、uniapp设置为history模式 2、nginx设置好转发规则 3、后端服务器(类同云函数),动态给模版html设置标题、描述、关键词(根据自己需要)返回html(注意:同uniapp h5 的首页html模版一致)

教程, 前置要求, 通过服务器转发,
必须能安装nginx, 以及 node.js, express 服务器框架

在宝塔, 配置反向代理配置文件, 如果是linux 注意格式问题

处理动态生成的HTML模板, 通配符匹配, uniapp前端路径都是pages/

8332, 为你的 node.js 中express 服务器框架的端口号
注意: 由于原来的系统要求, 配置了一个全局代理, 所以这个路由匹配转发需要在全局代理上面才能生效

location ~ ^/pages/.*{  
    proxy_pass http://127.0.0.1:8332;  
    proxy_http_version 1.1;  
    proxy_read_timeout 360s;     
    proxy_redirect off;   
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection "upgrade";  
    proxy_set_header Host $host;  
    proxy_set_header X-Real-IP $remote_addr;  
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
    proxy_set_header REMOTE-HOST $remote_addr;  

    add_header X-Cache $upstream_cache_status;  
}  

# 以下是原来的反向代理文件, 不用动  
location / {  
    proxy_pass http://127.0.0.1:8325;  
    proxy_http_version 1.1;  
    proxy_read_timeout 360s;     
    proxy_redirect off;   
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection "upgrade";  
    proxy_set_header Host $host;  
    proxy_set_header X-Real-IP $remote_addr;  
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
    proxy_set_header REMOTE-HOST $remote_addr;  

    add_header X-Cache $upstream_cache_status;  
    #Set Nginx Cache  

    set $static_filetKzRZE5L 0;  
    if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )  
    {  
        set $static_filetKzRZE5L 1;  
        expires 1m;  
    }  
    if ( $static_filetKzRZE5L = 0 )  
    {  
        add_header Cache-Control no-cache;  
    }  
}  
#PROXY-END/

在宝塔中安装node.js, 以及express服务器
其他linux系统可以用命令行安装,
参考教程 https://www.cnblogs.com/front-web/p/15672575.html

安装node.js, 记得设置命令行版本一致

安装完成后需要启动一个node.js的网站
首先在服务器目录下创建一个文件夹, 刚开始是空的

进入命令行终端 cd /www/wwwroot/你创建的文件夹命
在终端中运行以下命令来初始化Node.js项目:npm init -y
在终端中运行以下命令来安装Express: npm install express
安装成功后创建 views 文件夹, app.js 文件 , 修改package.json文件

package.json 启动脚本文件内容  
{  
  "name": "putao_seo",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "start": "node app.js",  
    "test": "echo \"Error: no test specified\" && exit 1"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "dependencies": {  
    "ejs": "^3.1.8",  
    "express": "^4.18.2"  
  }  
}

app.js 文件内容, 重点, 里面内容需要根据自己的网站配置

1. 端口号, 要和上面配置反向代理一致

app.listen(8332, () => {  
  console.log('Server is running on port 8332');  
  console.log('express服务器启动成功! 端口号:8332');  
});

2. 公共配置

const commonConfig = {  
    BASE_URL: 'http://al.jn1tea.com/', // 设置BASE_URL, 你的域名, 例如:  http://al.jn1tea.com/pages/goods_details 设置为http://al.jn1tea.com/  
    VUE_APP_INDEX_CSS_HASH: 'asxga454' //  uniapp 打包后会在static中生成一个css文件, index.xxx.css, 在这里填写  
};  

// 这里就是你的uniapp打包后的h5 每个页面的访问路径, seo优化就在这里修改title, description, keywords

// 想优化哪个页面就继续添加

app.get('/pages/goods_cate/goods_cate', (req, res) => {  
    const pageData = {  
        title: '商品分类页',  
        description: '商品分类页描述',  
        keywords: '商品, 分类',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});

// 下面是全部的源码, 根据个人网站自行修改

const express = require('express');  
const ejs = require('ejs');  
const path = require('path');  

const app = express();  

// 设置模板引擎  
app.set('view engine', 'ejs');  
app.set('views', path.join(__dirname, 'views'));  

// 静态文件目录  
app.use(express.static(path.join(__dirname, 'public')));  

// 公共配置  
const commonConfig = {  
    BASE_URL: 'http://xxx.xxxcom/', // 根据实际情况设置BASE_URL  
    VUE_APP_INDEX_CSS_HASH: 'xxx' // 根据实际情况设置VUE_APP_INDEX_CSS_HASH  
};  

// 动态生成HTML  
app.get('/pages/goods_cate/goods_cate', (req, res) => {  
    const pageData = {  
        title: '商品分类页',  
        description: '商品分类页描述',  
        keywords: '商品, 分类',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});  

// 添加新的路由处理 /pages/store/home/index  
app.get('/pages/store/home/index', (req, res) => {  
    const pageData = {  
        title: '店铺首页',  
        description: '店铺首页描述',  
        keywords: '店铺, 首页',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});  

app.listen(8332, () => {  
  console.log('Server is running on port 8332');  
  console.log('express服务器启动成功! 端口号:8332');  
});

进入views文件夹, 创建index.ejs 文件

// 配置文件, 刚才在app.js 的文件会动态解析到这里的title等标签中

<!DOCTYPE html>  
<html lang="zh-CN">  
    <head>  
        <meta charset="utf-8">  
        <meta http-equiv="X-UA-Compatible" content="IE=edge">  
        <title><%= title %> | 葡萄有约</title>  
        <meta name="Keywords" content="<%= keywords %>" />  
        <meta name="Description" content="<%= description %>" />  

        <script>  
            var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))  
            document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')  
            if(window.location.protocol == 'http:'){  
                document.write('<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">')  
            }  
        </script>  
        <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />  
    </head>  
    <body>  
        <noscript>  
            <strong>Please enable JavaScript to continue.</strong>  
        </noscript>  
        <div id="app"></div>  
        <!-- built files will be auto injected -->  
    </body>  
</html>

接下来创建一个node.js 网站

启动网站,

cd进入刚才初始化创建的目录, 用终端打开
输入命令 node app.js 启动express 服务器, 看到日志说明启动成功

注意, 如果中途修改配置文件, 记得重启 node app.js, 同理nginx 修改也要重启生效
如果没问题, 就可以访问你配置后的页面, ctrl + u 查看是否生效

继续阅读 »

基于nginx服务器优化的方案, 适用于 uniapp开发的网站, 可适用于老项目

由于官网的插件暂时不支持老的项目,所以使用这种方法
本教程亲测可用, 以及上线的项目网址: http://al.jn1tea.com/
打开调试工具, 手机模式, ctrl + u 可以查看每个页面的 seo内容**

教程内容有点长, 请耐心看完

1、uniapp设置为history模式 2、nginx设置好转发规则 3、后端服务器(类同云函数),动态给模版html设置标题、描述、关键词(根据自己需要)返回html(注意:同uniapp h5 的首页html模版一致)

教程, 前置要求, 通过服务器转发,
必须能安装nginx, 以及 node.js, express 服务器框架

在宝塔, 配置反向代理配置文件, 如果是linux 注意格式问题

处理动态生成的HTML模板, 通配符匹配, uniapp前端路径都是pages/

8332, 为你的 node.js 中express 服务器框架的端口号
注意: 由于原来的系统要求, 配置了一个全局代理, 所以这个路由匹配转发需要在全局代理上面才能生效

location ~ ^/pages/.*{  
    proxy_pass http://127.0.0.1:8332;  
    proxy_http_version 1.1;  
    proxy_read_timeout 360s;     
    proxy_redirect off;   
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection "upgrade";  
    proxy_set_header Host $host;  
    proxy_set_header X-Real-IP $remote_addr;  
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
    proxy_set_header REMOTE-HOST $remote_addr;  

    add_header X-Cache $upstream_cache_status;  
}  

# 以下是原来的反向代理文件, 不用动  
location / {  
    proxy_pass http://127.0.0.1:8325;  
    proxy_http_version 1.1;  
    proxy_read_timeout 360s;     
    proxy_redirect off;   
    proxy_set_header Upgrade $http_upgrade;  
    proxy_set_header Connection "upgrade";  
    proxy_set_header Host $host;  
    proxy_set_header X-Real-IP $remote_addr;  
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
    proxy_set_header REMOTE-HOST $remote_addr;  

    add_header X-Cache $upstream_cache_status;  
    #Set Nginx Cache  

    set $static_filetKzRZE5L 0;  
    if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )  
    {  
        set $static_filetKzRZE5L 1;  
        expires 1m;  
    }  
    if ( $static_filetKzRZE5L = 0 )  
    {  
        add_header Cache-Control no-cache;  
    }  
}  
#PROXY-END/

在宝塔中安装node.js, 以及express服务器
其他linux系统可以用命令行安装,
参考教程 https://www.cnblogs.com/front-web/p/15672575.html

安装node.js, 记得设置命令行版本一致

安装完成后需要启动一个node.js的网站
首先在服务器目录下创建一个文件夹, 刚开始是空的

进入命令行终端 cd /www/wwwroot/你创建的文件夹命
在终端中运行以下命令来初始化Node.js项目:npm init -y
在终端中运行以下命令来安装Express: npm install express
安装成功后创建 views 文件夹, app.js 文件 , 修改package.json文件

package.json 启动脚本文件内容  
{  
  "name": "putao_seo",  
  "version": "1.0.0",  
  "description": "",  
  "main": "index.js",  
  "scripts": {  
    "start": "node app.js",  
    "test": "echo \"Error: no test specified\" && exit 1"  
  },  
  "keywords": [],  
  "author": "",  
  "license": "ISC",  
  "dependencies": {  
    "ejs": "^3.1.8",  
    "express": "^4.18.2"  
  }  
}

app.js 文件内容, 重点, 里面内容需要根据自己的网站配置

1. 端口号, 要和上面配置反向代理一致

app.listen(8332, () => {  
  console.log('Server is running on port 8332');  
  console.log('express服务器启动成功! 端口号:8332');  
});

2. 公共配置

const commonConfig = {  
    BASE_URL: 'http://al.jn1tea.com/', // 设置BASE_URL, 你的域名, 例如:  http://al.jn1tea.com/pages/goods_details 设置为http://al.jn1tea.com/  
    VUE_APP_INDEX_CSS_HASH: 'asxga454' //  uniapp 打包后会在static中生成一个css文件, index.xxx.css, 在这里填写  
};  

// 这里就是你的uniapp打包后的h5 每个页面的访问路径, seo优化就在这里修改title, description, keywords

// 想优化哪个页面就继续添加

app.get('/pages/goods_cate/goods_cate', (req, res) => {  
    const pageData = {  
        title: '商品分类页',  
        description: '商品分类页描述',  
        keywords: '商品, 分类',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});

// 下面是全部的源码, 根据个人网站自行修改

const express = require('express');  
const ejs = require('ejs');  
const path = require('path');  

const app = express();  

// 设置模板引擎  
app.set('view engine', 'ejs');  
app.set('views', path.join(__dirname, 'views'));  

// 静态文件目录  
app.use(express.static(path.join(__dirname, 'public')));  

// 公共配置  
const commonConfig = {  
    BASE_URL: 'http://xxx.xxxcom/', // 根据实际情况设置BASE_URL  
    VUE_APP_INDEX_CSS_HASH: 'xxx' // 根据实际情况设置VUE_APP_INDEX_CSS_HASH  
};  

// 动态生成HTML  
app.get('/pages/goods_cate/goods_cate', (req, res) => {  
    const pageData = {  
        title: '商品分类页',  
        description: '商品分类页描述',  
        keywords: '商品, 分类',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});  

// 添加新的路由处理 /pages/store/home/index  
app.get('/pages/store/home/index', (req, res) => {  
    const pageData = {  
        title: '店铺首页',  
        description: '店铺首页描述',  
        keywords: '店铺, 首页',  
        ...commonConfig  
    };  
    res.render('index', pageData);  
});  

app.listen(8332, () => {  
  console.log('Server is running on port 8332');  
  console.log('express服务器启动成功! 端口号:8332');  
});

进入views文件夹, 创建index.ejs 文件

// 配置文件, 刚才在app.js 的文件会动态解析到这里的title等标签中

<!DOCTYPE html>  
<html lang="zh-CN">  
    <head>  
        <meta charset="utf-8">  
        <meta http-equiv="X-UA-Compatible" content="IE=edge">  
        <title><%= title %> | 葡萄有约</title>  
        <meta name="Keywords" content="<%= keywords %>" />  
        <meta name="Description" content="<%= description %>" />  

        <script>  
            var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))  
            document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')  
            if(window.location.protocol == 'http:'){  
                document.write('<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">')  
            }  
        </script>  
        <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />  
    </head>  
    <body>  
        <noscript>  
            <strong>Please enable JavaScript to continue.</strong>  
        </noscript>  
        <div id="app"></div>  
        <!-- built files will be auto injected -->  
    </body>  
</html>

接下来创建一个node.js 网站

启动网站,

cd进入刚才初始化创建的目录, 用终端打开
输入命令 node app.js 启动express 服务器, 看到日志说明启动成功

注意, 如果中途修改配置文件, 记得重启 node app.js, 同理nginx 修改也要重启生效
如果没问题, 就可以访问你配置后的页面, ctrl + u 查看是否生效

收起阅读 »

团队接单!诚心做事,敏捷团队,线上案例多

团队成员来自深圳、上海杭州等地,人均十年工作经验,现回家四线城市发展

团队成员在一起(敏捷团队)
前端全栈,主要围绕Uniapp、Vue2,3,React等
后端全栈,主要以Java、PHP、Golang三者为主
服务端,精通服务器部署,Docker部署,运维

现有第三方资源清单
1、在线支付(费率优惠)
2、服务器共享(合作后上线初期或者中小项目免费部署使用)
3、域名商业化共享(二级域名)

有以上几点可以快速满足需求落地,直接利用我方已有的资源

以定制需求制作系统为主,根据需求初步制作功能清单,评估工时进行报价,价格合理欢迎来谈,有需要的加V或电联:(尧)13539565631

继续阅读 »

团队成员来自深圳、上海杭州等地,人均十年工作经验,现回家四线城市发展

团队成员在一起(敏捷团队)
前端全栈,主要围绕Uniapp、Vue2,3,React等
后端全栈,主要以Java、PHP、Golang三者为主
服务端,精通服务器部署,Docker部署,运维

现有第三方资源清单
1、在线支付(费率优惠)
2、服务器共享(合作后上线初期或者中小项目免费部署使用)
3、域名商业化共享(二级域名)

有以上几点可以快速满足需求落地,直接利用我方已有的资源

以定制需求制作系统为主,根据需求初步制作功能清单,评估工时进行报价,价格合理欢迎来谈,有需要的加V或电联:(尧)13539565631

收起阅读 »

vue3兼容APP和微信小程序的base64图片保存到相册的方法

<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>

API请求获取得到buffer

codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer

由于个人原因小程序端fields获取的context接连抽风绘制不出图形

uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})

所以小程序只能从canvas入手,最终


// 确保canvas已经挂载后执行下面的代码片段  

const tempFilePath = ref("")  
// #ifdef APP  
                    const ctx = uni.createCanvasContext("myCanvas", app.proxy)  

                    ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))  
                    ctx.setFillStyle('white')  
                    ctx.fill()  
                    ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(  
                        670), uni.upx2px(670));  

                    // !!!一定要在回调中获得这个canvas的临时地址  
                    ctx.draw(false, async () => {  

                        uni.canvasToTempFilePath({  
                            canvasId: "myCanvas",  
                            success: function(res) {  
                                console.log(res  
                                    .tempFilePath)  
                                tempFilePath.value = res  
                                    .tempFilePath  

                                // 能预览就是画成功  
                                // uni.previewImage({  
                                //  urls: [res  
                                //      .tempFilePath  
                                //  ],  
                                // })  
                            }  
                        })  
                    })  

                    // #endif  

                    // #ifdef MP  

                    // 小程序废弃了createCanvasContext  
                    const query = uni.createSelectorQuery().in(app.proxy)  
                    query.select('#myCanvas')  
                        .fields({  
                            node: true,  
                            size: true  
                        })  
                        .exec(async (res) => {  
                            // console.log(res)  
                            let canvas = res[0].node  
                            let ctx = canvas.getContext('2d')  
                            // console.log(ctx, canvas)  

                            const dpr = wx.getSystemInfoSync().pixelRatio  
                            canvas.width = res[0].width * dpr  
                            canvas.height = res[0].height * dpr  
                            ctx.scale(dpr, dpr)  

                            const fsm = wx.getFileSystemManager() // 文件管理器  
                            const fname = app.proxy.$utils.$helper.generateRandomString(16)  
                            const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名  
                            const format = 'png' // 文件后缀  
                            const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制  
                            const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名  

                            fsm.writeFile({ // 写文件  
                                filePath,  
                                data: buffer,  
                                encoding: 'binary',  
                                success: (res) => {  
                                    // 能预览就是画成功  
                                    // wx.previewImage({  
                                    //  urls: [filePath],  
                                    // })  
                                    var img = canvas.createImage();  
                                    img.src = filePath  
                                    img.onload = function() {  
                                        ctx.drawImage(img, 0, 0,  
                                            uni  
                                            .upx2px(  
                                                670), uni.upx2px(670));  
                                        // ctx.draw()  

                                        uni.canvasToTempFilePath({  
                                            canvasId: 'myCanvas',  
                                            canvas: canvas,  
                                            success: function(res) {  
                                                console.log(res  
                                                    .tempFilePath)  
                                                tempFilePath.value = res  
                                                    .tempFilePath  
                                            },  
                                            fail: function(error) {  
                                                console.error(error)  
                                            }  
                                        }, app.proxy);  
                                    }  

                                },  
                                fail: (err) => {  
                                    console.error(err)  
                                }  
                            })  
                        })  
                    // #endif  

// 保存到相册  
const saveCode = () => {  
        uni.saveImageToPhotosAlbum({  
            filePath: tempFilePath.value,  
            success: function() {  
                uni.showToast({  
                    title: '保存成功',  
                    icon: 'success'  
                });  
            },  
            fail: function(error) {  
                uni.showToast({  
                    title: '未保存成功',  
                    icon: 'none'  
                });  
            }  
        });  
    }
继续阅读 »

<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>

API请求获取得到buffer

codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer

由于个人原因小程序端fields获取的context接连抽风绘制不出图形

uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})

所以小程序只能从canvas入手,最终


// 确保canvas已经挂载后执行下面的代码片段  

const tempFilePath = ref("")  
// #ifdef APP  
                    const ctx = uni.createCanvasContext("myCanvas", app.proxy)  

                    ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))  
                    ctx.setFillStyle('white')  
                    ctx.fill()  
                    ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(  
                        670), uni.upx2px(670));  

                    // !!!一定要在回调中获得这个canvas的临时地址  
                    ctx.draw(false, async () => {  

                        uni.canvasToTempFilePath({  
                            canvasId: "myCanvas",  
                            success: function(res) {  
                                console.log(res  
                                    .tempFilePath)  
                                tempFilePath.value = res  
                                    .tempFilePath  

                                // 能预览就是画成功  
                                // uni.previewImage({  
                                //  urls: [res  
                                //      .tempFilePath  
                                //  ],  
                                // })  
                            }  
                        })  
                    })  

                    // #endif  

                    // #ifdef MP  

                    // 小程序废弃了createCanvasContext  
                    const query = uni.createSelectorQuery().in(app.proxy)  
                    query.select('#myCanvas')  
                        .fields({  
                            node: true,  
                            size: true  
                        })  
                        .exec(async (res) => {  
                            // console.log(res)  
                            let canvas = res[0].node  
                            let ctx = canvas.getContext('2d')  
                            // console.log(ctx, canvas)  

                            const dpr = wx.getSystemInfoSync().pixelRatio  
                            canvas.width = res[0].width * dpr  
                            canvas.height = res[0].height * dpr  
                            ctx.scale(dpr, dpr)  

                            const fsm = wx.getFileSystemManager() // 文件管理器  
                            const fname = app.proxy.$utils.$helper.generateRandomString(16)  
                            const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名  
                            const format = 'png' // 文件后缀  
                            const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制  
                            const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名  

                            fsm.writeFile({ // 写文件  
                                filePath,  
                                data: buffer,  
                                encoding: 'binary',  
                                success: (res) => {  
                                    // 能预览就是画成功  
                                    // wx.previewImage({  
                                    //  urls: [filePath],  
                                    // })  
                                    var img = canvas.createImage();  
                                    img.src = filePath  
                                    img.onload = function() {  
                                        ctx.drawImage(img, 0, 0,  
                                            uni  
                                            .upx2px(  
                                                670), uni.upx2px(670));  
                                        // ctx.draw()  

                                        uni.canvasToTempFilePath({  
                                            canvasId: 'myCanvas',  
                                            canvas: canvas,  
                                            success: function(res) {  
                                                console.log(res  
                                                    .tempFilePath)  
                                                tempFilePath.value = res  
                                                    .tempFilePath  
                                            },  
                                            fail: function(error) {  
                                                console.error(error)  
                                            }  
                                        }, app.proxy);  
                                    }  

                                },  
                                fail: (err) => {  
                                    console.error(err)  
                                }  
                            })  
                        })  
                    // #endif  

// 保存到相册  
const saveCode = () => {  
        uni.saveImageToPhotosAlbum({  
            filePath: tempFilePath.value,  
            success: function() {  
                uni.showToast({  
                    title: '保存成功',  
                    icon: 'success'  
                });  
            },  
            fail: function(error) {  
                uni.showToast({  
                    title: '未保存成功',  
                    icon: 'none'  
                });  
            }  
        });  
    }
收起阅读 »

分享自用HBuilderX主题 仿 VsCode Default Dark Modern主题

主题 HBuilderX

自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题

有一些缺陷,比如:

  • 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
  • 没有修改代码颜色,是酷黑主题原有的颜色
    如下图

主题预览图:

{  
    "editor.colorScheme": "Monokai",  
    "workbench.colorCustomizations": {  
        "[Default]": {},  
        "[Monokai]": {  
            "console.background":"#181818",  
            "menubar.background":"#181818",  
            "editor.background": "#1f1f1f",  
            "editor.foreground": "#808080",  
            "editor.indentguide": "#404040",  
            "editor.indicator.sameword": "#343a40",  
            "editor.selectRegion": "#2a2b2d",  
            "editor.selection": "#264f78",  
            "editor.unactive_selection.background": "#9e6a03",  
            "editor.whitespace": "#1f1f1f",  
            "editorGroup.border": "#333333",  
            "editorGroupHeader.tabsBackground": "#181818",  
            "editorSuggestWidget.background": "#202020",  
            "editorSuggestWidget.border": "#454545",  
            "editorSuggestWidget.selectedBackground": "#454545",  
            "focusBorder": "#0078d4",  
            "input.background": "#313131",  
            "input.foreground": "#c3c3c3",  
            "input.searchbar.foreground": "#989898",  
            "input.searchbar.foreground.notfinded": "#aeaeae",  
            "inputList.border": "#313131",  
            "inputList.foreground": "#8b8b8b",  
            "inputList.hoverBackground": "#2a2d2e",  
            "inputList.titleColor": "#cccccc",  
            "inputValidation.infoBackground": "#222222",  
            "list.activeSelectionBackground": "#04395e",  
            "list.activeSelectionForeground": "#ffffff",  
            "list.foreground": "#cccccc",  
            "list.highlightForeground": "#ffffff",  
            "list.hoverBackground": "#2a2d2e",  
            "minimap.handle.background": "#1f1f1f",  
            "outlineBackground": "#1f1f1f",  
            "scrollbarSlider.background": "#434343",  
            "scrollbarSlider.hoverBackground": "#4f4f4f",  
            "sideBar.background": "#181818",  
            "sideBar.border": "#2b2b2b",  
            "statusBar.background": "#181818",  
            "statusBar.button.hoverbackground": "#343434",  
            "statusBar.foreground": "#cccccc",  
            "tab.activeBackground": "#1f1f1f",  
            "tab.activeForeground": "#ffffff",  
            "tab.border": "#2b2b2b",  
            "tab.hoverBackground": "#1f1f1f",  
            "tab.inactiveBackground": "#181818",  
            "tab.inactiveForeground": "#9d9d9d",  
            "tab.unfocusedActiveForeground": "#737373",  
            "tab.unfocusedHoverBackground": "#1f1f1f",  
            "tab.unfocusedInactiveForeground": "#181818",  
            "terminal.background": "#181818",  
            "toolBar.background": "#181818",  
            "toolBar.border": "#2b2b2b",  
            "toolBar.hoverBackground": "#2d2e2e"  
        }  
    },  
    "editor.tokenColorCustomizations": {  
        "[Default]": {},  
        "[Monokai]": {  
            "rules": [  
                {  
                    "scope": [  
                        "comment"  
                    ],  
                    "settings": {  
                        "foreground": "#6a9955"  
                    }  
                }  
            ]  
        }  
    }  
}  
继续阅读 »

自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题

有一些缺陷,比如:

  • 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
  • 没有修改代码颜色,是酷黑主题原有的颜色
    如下图

主题预览图:

{  
    "editor.colorScheme": "Monokai",  
    "workbench.colorCustomizations": {  
        "[Default]": {},  
        "[Monokai]": {  
            "console.background":"#181818",  
            "menubar.background":"#181818",  
            "editor.background": "#1f1f1f",  
            "editor.foreground": "#808080",  
            "editor.indentguide": "#404040",  
            "editor.indicator.sameword": "#343a40",  
            "editor.selectRegion": "#2a2b2d",  
            "editor.selection": "#264f78",  
            "editor.unactive_selection.background": "#9e6a03",  
            "editor.whitespace": "#1f1f1f",  
            "editorGroup.border": "#333333",  
            "editorGroupHeader.tabsBackground": "#181818",  
            "editorSuggestWidget.background": "#202020",  
            "editorSuggestWidget.border": "#454545",  
            "editorSuggestWidget.selectedBackground": "#454545",  
            "focusBorder": "#0078d4",  
            "input.background": "#313131",  
            "input.foreground": "#c3c3c3",  
            "input.searchbar.foreground": "#989898",  
            "input.searchbar.foreground.notfinded": "#aeaeae",  
            "inputList.border": "#313131",  
            "inputList.foreground": "#8b8b8b",  
            "inputList.hoverBackground": "#2a2d2e",  
            "inputList.titleColor": "#cccccc",  
            "inputValidation.infoBackground": "#222222",  
            "list.activeSelectionBackground": "#04395e",  
            "list.activeSelectionForeground": "#ffffff",  
            "list.foreground": "#cccccc",  
            "list.highlightForeground": "#ffffff",  
            "list.hoverBackground": "#2a2d2e",  
            "minimap.handle.background": "#1f1f1f",  
            "outlineBackground": "#1f1f1f",  
            "scrollbarSlider.background": "#434343",  
            "scrollbarSlider.hoverBackground": "#4f4f4f",  
            "sideBar.background": "#181818",  
            "sideBar.border": "#2b2b2b",  
            "statusBar.background": "#181818",  
            "statusBar.button.hoverbackground": "#343434",  
            "statusBar.foreground": "#cccccc",  
            "tab.activeBackground": "#1f1f1f",  
            "tab.activeForeground": "#ffffff",  
            "tab.border": "#2b2b2b",  
            "tab.hoverBackground": "#1f1f1f",  
            "tab.inactiveBackground": "#181818",  
            "tab.inactiveForeground": "#9d9d9d",  
            "tab.unfocusedActiveForeground": "#737373",  
            "tab.unfocusedHoverBackground": "#1f1f1f",  
            "tab.unfocusedInactiveForeground": "#181818",  
            "terminal.background": "#181818",  
            "toolBar.background": "#181818",  
            "toolBar.border": "#2b2b2b",  
            "toolBar.hoverBackground": "#2d2e2e"  
        }  
    },  
    "editor.tokenColorCustomizations": {  
        "[Default]": {},  
        "[Monokai]": {  
            "rules": [  
                {  
                    "scope": [  
                        "comment"  
                    ],  
                    "settings": {  
                        "foreground": "#6a9955"  
                    }  
                }  
            ]  
        }  
    }  
}  
收起阅读 »

uni-app 最专业的代码生成器

Universal Links自动生成指南 uni_app

mui 专业代码生成器

1.数据库专业工具

  1. 后端专业工具
  2. UI 采用MUI 一键生成

欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950

mui 专业代码生成器

1.数据库专业工具

  1. 后端专业工具
  2. UI 采用MUI 一键生成

欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950

技术分享:从崩溃边缘到问题解决 —— SSL证书兼容性问题的实战经历

小程序

引言

作为一名开发者,我们经常会遇到一些令人头疼的技术难题。有时候,这些问题看似简单却异常棘手,让人几乎要放弃。今天,我想分享一次特别的经历,它始于一系列的调试失败,最终却在不经意间找到了解决方案。这个故事围绕着SSL证书的兼容性问题展开,希望能给大家带来一些启示。

问题背景

我负责开发的一款小程序需要与后端API进行安全通信。为了保证数据传输的安全性和平台要求,我们采用了SSL/TLS协议,并为服务器配置了一张免费的SSL证书。起初一切看起来都很顺利,直到我们在进行跨平台测试时遇到了问题。

初步排查

我们的测试团队在不同的设备上进行了测试,大部分情况下一切正常,但有一个特定品牌的手机总是无法成功发起HTTPS请求。这个问题一开始并不明显,因为我们主要依赖于模拟器和主流机型进行测试。然而,随着用户反馈的增多,这个问题变得越来越紧迫。

排查步骤

  1. 日志分析:首先,我们查看了客户端的日志记录,发现了一些关于证书验证失败的错误提示。
  2. 网络监控:使用抓包工具对网络请求进行了监控,发现客户端在尝试建立HTTPS连接时收到了错误响应。
  3. 设备差异对比:我们将有问题的设备与其他设备进行了对比测试,试图找出它们之间的差异。

寻找线索

尽管我们进行了初步的排查,但问题仍然没有得到解决。我们开始怀疑是客户端代码的问题,甚至重写了部分网络请求逻辑,但结果依然不尽人意。正当我们几乎要放弃的时候,一个偶然的机会改变了这一切。

关键转折点

在又一次的调试过程中,由于免费证书到期太麻烦,更换一张一年期的付费的SSL证书进行测试。起初,这只是一种无意间的举措,我们并没有抱希望。然而,就在我们更换了证书之后,在那个一直存在问题的手机上进行测试时,奇迹发生了——请求成功了!

分析原因

这次意外的成功让我们意识到,问题可能出在免费SSL证书的兼容性上。为了验证这一猜想,我们进行了更深入的研究:

  1. 证书类型对比:我们比较了免费证书和付费证书之间的差异,特别是它们的验证方式和兼容性。
  2. 浏览器和操作系统兼容性:我们查阅了相关文档,了解了不同浏览器和操作系统对于SSL证书的要求。
  3. 设备特定问题:进一步研究了那款特定品牌的手机的操作系统版本和其他特性,发现它对于某些类型的证书支持较差。

解决方案

最终,我们确定了问题的根本原因是免费SSL证书在某些设备上的兼容性不佳。为了避免类似问题再次发生,我们采取了以下几个措施:

  1. 升级证书:将免费证书升级为付费证书,确保了更好的兼容性和安全性。
  2. 全面测试:增加了更多样化的设备和环境进行测试,确保应用程序在各种条件下都能正常运行。
  3. 用户教育:通过应用内的提示,告知用户如何检查他们的设备是否支持HTTPS连接。

结语

这次经历教会了我们几个重要的教训:

  • 不要忽视小众设备:即使是小众的设备也可能成为问题的关键。
  • 证书的选择很重要:选择合适的SSL证书对于确保应用的兼容性和安全性至关重要。
  • 持续学习:技术总是在不断进步,持续学习新技术和最佳实践可以帮助我们更好地应对挑战。

希望我的这次经历能对你有所帮助,当你面对类似的问题时,不要轻易放弃,

有时候解决之道可能就在不远处。

继续阅读 »

引言

作为一名开发者,我们经常会遇到一些令人头疼的技术难题。有时候,这些问题看似简单却异常棘手,让人几乎要放弃。今天,我想分享一次特别的经历,它始于一系列的调试失败,最终却在不经意间找到了解决方案。这个故事围绕着SSL证书的兼容性问题展开,希望能给大家带来一些启示。

问题背景

我负责开发的一款小程序需要与后端API进行安全通信。为了保证数据传输的安全性和平台要求,我们采用了SSL/TLS协议,并为服务器配置了一张免费的SSL证书。起初一切看起来都很顺利,直到我们在进行跨平台测试时遇到了问题。

初步排查

我们的测试团队在不同的设备上进行了测试,大部分情况下一切正常,但有一个特定品牌的手机总是无法成功发起HTTPS请求。这个问题一开始并不明显,因为我们主要依赖于模拟器和主流机型进行测试。然而,随着用户反馈的增多,这个问题变得越来越紧迫。

排查步骤

  1. 日志分析:首先,我们查看了客户端的日志记录,发现了一些关于证书验证失败的错误提示。
  2. 网络监控:使用抓包工具对网络请求进行了监控,发现客户端在尝试建立HTTPS连接时收到了错误响应。
  3. 设备差异对比:我们将有问题的设备与其他设备进行了对比测试,试图找出它们之间的差异。

寻找线索

尽管我们进行了初步的排查,但问题仍然没有得到解决。我们开始怀疑是客户端代码的问题,甚至重写了部分网络请求逻辑,但结果依然不尽人意。正当我们几乎要放弃的时候,一个偶然的机会改变了这一切。

关键转折点

在又一次的调试过程中,由于免费证书到期太麻烦,更换一张一年期的付费的SSL证书进行测试。起初,这只是一种无意间的举措,我们并没有抱希望。然而,就在我们更换了证书之后,在那个一直存在问题的手机上进行测试时,奇迹发生了——请求成功了!

分析原因

这次意外的成功让我们意识到,问题可能出在免费SSL证书的兼容性上。为了验证这一猜想,我们进行了更深入的研究:

  1. 证书类型对比:我们比较了免费证书和付费证书之间的差异,特别是它们的验证方式和兼容性。
  2. 浏览器和操作系统兼容性:我们查阅了相关文档,了解了不同浏览器和操作系统对于SSL证书的要求。
  3. 设备特定问题:进一步研究了那款特定品牌的手机的操作系统版本和其他特性,发现它对于某些类型的证书支持较差。

解决方案

最终,我们确定了问题的根本原因是免费SSL证书在某些设备上的兼容性不佳。为了避免类似问题再次发生,我们采取了以下几个措施:

  1. 升级证书:将免费证书升级为付费证书,确保了更好的兼容性和安全性。
  2. 全面测试:增加了更多样化的设备和环境进行测试,确保应用程序在各种条件下都能正常运行。
  3. 用户教育:通过应用内的提示,告知用户如何检查他们的设备是否支持HTTPS连接。

结语

这次经历教会了我们几个重要的教训:

  • 不要忽视小众设备:即使是小众的设备也可能成为问题的关键。
  • 证书的选择很重要:选择合适的SSL证书对于确保应用的兼容性和安全性至关重要。
  • 持续学习:技术总是在不断进步,持续学习新技术和最佳实践可以帮助我们更好地应对挑战。

希望我的这次经历能对你有所帮助,当你面对类似的问题时,不要轻易放弃,

有时候解决之道可能就在不远处。

收起阅读 »

使用了推送功能怎样生成推送证书

推送

使用了推送功能后,要生成推送证书,不过这个推送证书并不是用来打包的,推送证书的作用是放在推送平台里用来发送消息用的,生成了推送证书后,依然还需要生成打包证书。

我们这篇文章来说下,使用了推送功能后,证书和证书profile文件如何修改。

假如你用了推送功能,在苹果创建应用的时候,需要勾选上支持推送,创建identifiers(appId)的时候,要注意勾选下图的选项。

因此修改了苹果开发者中心的应用的属性,所以要重新生成证书,然后参考这篇文章先创建打包证书:https://www.yunedit.com/xueyuan/jx/uniappcreatecert

appId勾选了支持push的时候,是需要绑定一个推送证书的,所以你需要创建一个推送证书。

注意这个推送证书并不是用来打包的,创建推送证书的步骤跟上面链接的教程的流程几乎一样,可以先在香蕉云编生成一个csr文件,然后再去苹果开发者中心的certificates菜单,创建一个cer证书,然后回到香蕉云编上传这个cer文件,生成一个p12。(具体图文教程参考上面发的教程链接),和教程不同的是,创建cer文件的时候,需要选择推送类型,不是其他的类型。

这样,你会生成两个p12证书文件,一个是打包用的证书,一个是推送用的证书,还有一个证书profile文件。总共三个文件。其中打包证书p12文件和证书profile文件,是用来在uniapp打包用的,推送证书p12文件是用来放在推送平台发消息的。这里比较重要,不要用推送证书来打包哦。

继续阅读 »

使用了推送功能后,要生成推送证书,不过这个推送证书并不是用来打包的,推送证书的作用是放在推送平台里用来发送消息用的,生成了推送证书后,依然还需要生成打包证书。

我们这篇文章来说下,使用了推送功能后,证书和证书profile文件如何修改。

假如你用了推送功能,在苹果创建应用的时候,需要勾选上支持推送,创建identifiers(appId)的时候,要注意勾选下图的选项。

因此修改了苹果开发者中心的应用的属性,所以要重新生成证书,然后参考这篇文章先创建打包证书:https://www.yunedit.com/xueyuan/jx/uniappcreatecert

appId勾选了支持push的时候,是需要绑定一个推送证书的,所以你需要创建一个推送证书。

注意这个推送证书并不是用来打包的,创建推送证书的步骤跟上面链接的教程的流程几乎一样,可以先在香蕉云编生成一个csr文件,然后再去苹果开发者中心的certificates菜单,创建一个cer证书,然后回到香蕉云编上传这个cer文件,生成一个p12。(具体图文教程参考上面发的教程链接),和教程不同的是,创建cer文件的时候,需要选择推送类型,不是其他的类型。

这样,你会生成两个p12证书文件,一个是打包用的证书,一个是推送用的证书,还有一个证书profile文件。总共三个文件。其中打包证书p12文件和证书profile文件,是用来在uniapp打包用的,推送证书p12文件是用来放在推送平台发消息的。这里比较重要,不要用推送证书来打包哦。

收起阅读 »

uni.getLocation偶而获取不到,使用原生代码替换

uni.getlocation

在APP中一直使用uni.getLocation的系统定位模块获取模糊位置,用以查询同城文章。偶然发现最近升级代码后,ANDROID下uni.getLocation无法正常工作,返回error:2错误。在仔细检查后,怀疑是hbuilderx升级后的BUG。写了一段android原生代码工作正常,并在运行一次此代码获取到位置后,再使用uni.getLocation即能正常。有理由怀疑是uni.getLocation使用了getLastKnownLocation导致的,查android文档,getLastKnownLocation返回最近一次位置缓存,并不保证时效及是否有值。所以在运行这段代码后,缓存了位置值,此后uni.getLocation可以正常动作。
这是一段试验代码,并未加入超时、错误和权限检查等功能,只用于临时替换及检验uni.getLocation是否正常工作。
PS:时间原故未做更多研究,不确定是否是BUG,厂家有结果请予以告知。

        __getLocation = (options) => {  
                const p = new Promise((resolve, reject) => {  
                    const isNull = value => !value && reject({  
                        errMsg: "_getLocation fail."  
                    });  
                    isNull(options);  
                    isNull(options.success);  
                    isNull(typeof options.success === "function");  
                    const mainActivity = plus.android.runtimeMainActivity();  
                    isNull(mainActivity);  
                    const LOCATION_SERVICE = plus.android.getAttribute(mainActivity, "LOCATION_SERVICE");  
                    const locationManager = plus.android.invoke(mainActivity, "getSystemService",  
                        LOCATION_SERVICE);  
                    plus.android.autoCollection(mainActivity);  
                    isNull(locationManager);  
                    const criteria = plus.android.newObject("android.location.Criteria");  
                    isNull(criteria);  
                    const ACCURACY_COARSE = criteria.plusGetAttribute("ACCURACY_COARSE");  
                    plus.android.invoke(criteria, "setAccuracy", ACCURACY_COARSE);  
                    plus.android.invoke(criteria, "setAltitudeRequired", false);  
                    plus.android.invoke(criteria, "setBearingRequired", false);  
                    plus.android.invoke(criteria, "setCostAllowed", false);  
                    const POWER_LOW = criteria.plusGetAttribute("POWER_LOW");  
                    plus.android.invoke(criteria, "setPowerRequirement", POWER_LOW);  
                    const provider = plus.android.invoke(locationManager, "getBestProvider", criteria, true);  
                    plus.android.autoCollection(criteria);  
                    isNull(provider);  
                    const location = plus.android.invoke(locationManager, "getLastKnownLocation", provider);  
                    ////怀疑是此处无值导致原函数错误  
                    if (location) {  
                        const longitude = plus.android.invoke(location, "getLongitude");  
                        const latitude = plus.android.invoke(location, "getLatitude");  
                        plus.android.autoCollection(location);  
                        resolve({  
                            longitude,  
                            latitude  
                        });  
                    } else {  
                    ////location无值则进行监听至有值返回  
                        let instLocationListener = null;  
                        const locationListener = {  
                            "onLocationChanged": function(location) {  
                                if (location) {  
                                    const longitude = plus.android.invoke(location, "getLongitude");  
                                    const latitude = plus.android.invoke(location, "getLatitude");  
                                    plus.android.invoke(locationManager, "removeUpdates",  
                                        instLocationListener);  
                                    plus.android.autoCollection(instLocationListener);  
                                    plus.android.autoCollection(location);  
                                    resolve({  
                                        longitude,  
                                        latitude  
                                    });  
                                }  
                            },  
                            "onStatusChanged": function(provider, status, extras) {  
                                console.log(provider, status);  
                            },  
                            "onProviderEnabled": function(provider) {  
                                console.log(provider + " 启用了");  
                            },  
                            "onProviderDisabled": function(provider) {  
                                console.log(provider + " 关闭了");  
                            }  
                        }  
                        instLocationListener = plus.android.implements("android.location.LocationListener",  
                            locationListener);  
                        isNull(instLocationListener);  
                        plus.android.invoke(locationManager, "requestLocationUpdates", provider,  
                            3000, 10,  
                            instLocationListener);  
                    }  
                });  
                p.then(res => options.success(res)).catch(err => options.fail && options.fail(err));  
            };  
    __getLocation({  
        success: res => console.log(res)  
    });
继续阅读 »

在APP中一直使用uni.getLocation的系统定位模块获取模糊位置,用以查询同城文章。偶然发现最近升级代码后,ANDROID下uni.getLocation无法正常工作,返回error:2错误。在仔细检查后,怀疑是hbuilderx升级后的BUG。写了一段android原生代码工作正常,并在运行一次此代码获取到位置后,再使用uni.getLocation即能正常。有理由怀疑是uni.getLocation使用了getLastKnownLocation导致的,查android文档,getLastKnownLocation返回最近一次位置缓存,并不保证时效及是否有值。所以在运行这段代码后,缓存了位置值,此后uni.getLocation可以正常动作。
这是一段试验代码,并未加入超时、错误和权限检查等功能,只用于临时替换及检验uni.getLocation是否正常工作。
PS:时间原故未做更多研究,不确定是否是BUG,厂家有结果请予以告知。

        __getLocation = (options) => {  
                const p = new Promise((resolve, reject) => {  
                    const isNull = value => !value && reject({  
                        errMsg: "_getLocation fail."  
                    });  
                    isNull(options);  
                    isNull(options.success);  
                    isNull(typeof options.success === "function");  
                    const mainActivity = plus.android.runtimeMainActivity();  
                    isNull(mainActivity);  
                    const LOCATION_SERVICE = plus.android.getAttribute(mainActivity, "LOCATION_SERVICE");  
                    const locationManager = plus.android.invoke(mainActivity, "getSystemService",  
                        LOCATION_SERVICE);  
                    plus.android.autoCollection(mainActivity);  
                    isNull(locationManager);  
                    const criteria = plus.android.newObject("android.location.Criteria");  
                    isNull(criteria);  
                    const ACCURACY_COARSE = criteria.plusGetAttribute("ACCURACY_COARSE");  
                    plus.android.invoke(criteria, "setAccuracy", ACCURACY_COARSE);  
                    plus.android.invoke(criteria, "setAltitudeRequired", false);  
                    plus.android.invoke(criteria, "setBearingRequired", false);  
                    plus.android.invoke(criteria, "setCostAllowed", false);  
                    const POWER_LOW = criteria.plusGetAttribute("POWER_LOW");  
                    plus.android.invoke(criteria, "setPowerRequirement", POWER_LOW);  
                    const provider = plus.android.invoke(locationManager, "getBestProvider", criteria, true);  
                    plus.android.autoCollection(criteria);  
                    isNull(provider);  
                    const location = plus.android.invoke(locationManager, "getLastKnownLocation", provider);  
                    ////怀疑是此处无值导致原函数错误  
                    if (location) {  
                        const longitude = plus.android.invoke(location, "getLongitude");  
                        const latitude = plus.android.invoke(location, "getLatitude");  
                        plus.android.autoCollection(location);  
                        resolve({  
                            longitude,  
                            latitude  
                        });  
                    } else {  
                    ////location无值则进行监听至有值返回  
                        let instLocationListener = null;  
                        const locationListener = {  
                            "onLocationChanged": function(location) {  
                                if (location) {  
                                    const longitude = plus.android.invoke(location, "getLongitude");  
                                    const latitude = plus.android.invoke(location, "getLatitude");  
                                    plus.android.invoke(locationManager, "removeUpdates",  
                                        instLocationListener);  
                                    plus.android.autoCollection(instLocationListener);  
                                    plus.android.autoCollection(location);  
                                    resolve({  
                                        longitude,  
                                        latitude  
                                    });  
                                }  
                            },  
                            "onStatusChanged": function(provider, status, extras) {  
                                console.log(provider, status);  
                            },  
                            "onProviderEnabled": function(provider) {  
                                console.log(provider + " 启用了");  
                            },  
                            "onProviderDisabled": function(provider) {  
                                console.log(provider + " 关闭了");  
                            }  
                        }  
                        instLocationListener = plus.android.implements("android.location.LocationListener",  
                            locationListener);  
                        isNull(instLocationListener);  
                        plus.android.invoke(locationManager, "requestLocationUpdates", provider,  
                            3000, 10,  
                            instLocationListener);  
                    }  
                });  
                p.then(res => options.success(res)).catch(err => options.fail && options.fail(err));  
            };  
    __getLocation({  
        success: res => console.log(res)  
    });
收起阅读 »

找一个懂安卓原生+uniapp插件包兼职开发

需要做一个安卓原生插件包,供uniapp原生代码调用;

主要需求: 自定义扫条码样式功能、自定义扫二维码样式功能、个别特定原生实现需求提供API供uniapp调用。

需要做一个安卓原生插件包,供uniapp原生代码调用;

主要需求: 自定义扫条码样式功能、自定义扫二维码样式功能、个别特定原生实现需求提供API供uniapp调用。

如何在GitHub免费搭建个人博客网站?

  如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)

  步骤一:准备 GitHub 账户

  如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。

  步骤二:创建 GitHub 仓库

  登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。

  步骤三:下载 Jekyll 主题

  Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。

  步骤四:上传文件到 GitHub 仓库

  将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。

  步骤五:访问你的博客网站

  等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。

  步骤六:定制你的博客

  编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。

  通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。

继续阅读 »

  如何在GitHub免费搭建个人博客网站?当你想要开始自己的博客之旅,但又不想花费金钱购买服务器和域名时,还有一些免费的平台可供你选择。以下是一种无需服务器和域名的方法,利用GitHub Pages和Jekyll搭建个人博客网站(http://m.bokequ.com/list/22-0.html)

  步骤一:准备 GitHub 账户

  如果你还没有 GitHub 账户,首先需要注册一个。GitHub 提供免费的代码托管服务,同时也支持通过 GitHub Pages 托管静态网站。

  步骤二:创建 GitHub 仓库

  登录你的 GitHub 账户,点击右上角的加号按钮,选择 "New repository"。在 "Repository name" 栏中输入你的用户名(或者你希望的博客地址),比如 yourusername.github.io(注意替换成你的用户名)。勾选 "Initialize this repository with a README" 选项,并点击 "Create repository"。

  步骤三:下载 Jekyll 主题

  Jekyll 是一个简单易用的静态网站生成器,GitHub Pages 支持使用 Jekyll 搭建个人网站。你可以在 Jekyll 官方网站(https://jekyllrb.com/)或 GitHub 上找到各种免费的 Jekyll 主题。选择一个你喜欢的主题,将其下载并解压缩到本地。

  步骤四:上传文件到 GitHub 仓库

  将 Jekyll 主题文件夹中的所有文件上传到你在步骤二中创建的 GitHub 仓库中。你可以使用 GitHub Desktop、Git 命令行或者直接通过 GitHub 网站上传文件。

  步骤五:访问你的博客网站

  等待一段时间,GitHub 会自动构建你的网站,并将其托管在bokequ.github.io这个地址上。你可以在浏览器中输入这个地址,访问你的个人博客网站。

  步骤六:定制你的博客

  编辑 Jekyll 主题文件夹中的配置文件和内容文件,定制你的个人博客。你可以修改页面布局、添加新的页面和文章,以及调整样式和颜色。

  通过 GitHub Pages 和 Jekyll,你可以免费搭建个人博客网站,无需购买服务器和域名。这是一个简单且经济高效的方式,让你能够开始你的博客之旅,并与世界分享你的想法和创作。

收起阅读 »