本人查阅了许多资料,网上大部分的描述都比较模棱两可,我这里就将我的想法分享出来提供大家学习。
在这里实现一码多用的功能指的是 同个二维码在不同端扫出的结果不一样 例如微信扫跳出 微信小程序,支付宝扫跳出 支付宝小程序,内部APP扫码跳 内部页面等等。
1、实现流程
1.1、流程图
1.2、详细流程步骤
1、 是生成二维码,链接是前端H5界面的链接
2、 用户扫一扫的时候就会根据扫码的APP进行判断,其中微信扫一扫如果要 跳转小程序 的话需要在 微信公众平台 配置,而且小程序 暂不支持个人类型小程序开启此功能。相关配置操作如下:
-
配置二维码规则跳转二维码
二维码规则: 微信api里说的很清楚了
1、二维码规则的域名须通过ICP备案的验证。
2、支持http、https、ftp开头的链接(如:http://wx.qq.com、https://wx.qq.com/mp/、https://wx.qq.com/mp?id=123)。
3、一个小程序帐号可配置不多于10个二维码前缀规则。前缀占用规则:
开发者可选择是否占用符合二维码匹配规则的所有子规则。如选择占用,则其他帐号不可申请使用满足该前缀匹配规则的其他子规则。
如:若开发者A配置二维码规则:https://wx.qq.com/mp?id=123,并选择“占用所有子规则“,其他开发者将不可以配置满足前缀匹配的子规则如https://wx.qq.com/mp?id=1234。
3、内置APP需要在扫码端进行判断对应扫码内容并进行处理。如果识别到对应的 H5页面 和 带有对应的参数 就跳转到 对应APP内部页面,如果是其他页面则跳转至单页面,展示复制并打开浏览器即可查看网站/展示对应的内容,这样就实现了APP扫码跳转功能。
2、后端实现
2.1、准备工作
- 下载的网站链接 https://packagist.org/packages/yansongda/pay?query=Endroid%5CQrCode
- 选择生成二维码包,这里我推荐使用 endroid/qr-code
2.2、代码实现
- 根据内容安装依赖包后,我们开始封装生成二维码服务类
<?php
namespace app\common\service;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
use think\Hook;
class QrcodeService
{
/**
* 生成二维码
* @param string $content 生成二维码的内容
* @param int $userId 用户ID,默认为0
* @param string $logoImg 中间logo的图片本地路径
* @param int $logoWidth 中间logo的宽度
* @param int $logoHeight 中间logo的长度
* @return mixed
* @throws \Endroid\QrCode\Exception\InvalidPathException
*/
public function create($content, $userId = 0, $logoImg = 0, $logoWidth = 50, $logoHeight = 50)
{
if(!$logoImg) $logoImg = ASSETS_PATH . 'img/qrcode.png';
$qrCode = new QrCode($content);
$qrCode->setSize(300);
$qrCode->setWriterByName('png');
$qrCode->setMargin(10);
$qrCode->setEncoding('UTF-8');
$qrCode->setErrorCorrectionLevel(ErrorCorrectionLevel::HIGH());
$qrCode->setForegroundColor(['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0]);
$qrCode->setBackgroundColor(['r' => 255, 'g' => 255, 'b' => 255, 'a' => 0]);
// $qrCode->setLabel('Scan the code', 16, __PUBLIC__.'/../assets/fonts/noto_sans.otf', LabelAlignment::CENTER());
$qrCode->setLogoPath($logoImg); //设置LOGO
$qrCode->setLogoSize($logoWidth, $logoHeight);
$qrCode->setRoundBlockSize(true);
$qrCode->setValidateResult(false);
$qrCode->setWriterOptions(['exclude_xml_declaration' => true]);
// Directly output the QR code
header('Content-Type: ' . $qrCode->getContentType());
// Save it to a file
$dir = 'qrCode/' . date('Ymd', time()) . '/';
if (!file_exists($dir)) mkdir($dir, 0777, true);
//文件名称
$dirUrl = $dir . 'qrCode.png';
$url = PUBLIC_PATH . $dirUrl;
if ($userId) $url = PUBLIC_PATH . $dir . $userId . '-qrCode.png';
//写入本地
$qrCode->writeFile($url);
//保存到OSS
$urlOss = Hook::listen("upload_oss", $url, null, true);
//删除本地图片和文件夹
if (file_exists($url)) {
unlink($url);
rmdir($dir);
}
return $urlOss;
}
}
上面代码可以根据自己业务需求进行修改,我这里将二维码生成后 上传到OSS
- 创建个人二维码
<?php
namespace app\api\controller;
use app\common\controller\Api;
use app\common\service\QrcodeService;
use app\common\service\RedisService;
use app\common\service\WeChatService;
/**
* 二维码接口
* @package app\api\controller
*/
class Code extends Api
{
public function createSelfQrCode()
{
$redis = RedisService::connect();
$user = $this->auth->getUser();
$userId = $user['id'];
$avatar = $user['avatar'];
//判断Redis是否存在
$imgUrl = $redis->get(RedisService::SU_QRCODE_SELF_USER . $userId);
if (!$imgUrl) {
//调用中转页面,type=1 个人二维码
$h5Domain = db('sulink_setting')->where('id', 1)->value('h5_domain');
$path = $h5Domain . 'pages/index/info/index?user_id=' . $userId . '&type=1';
$imgUrl = (new QrcodeService)->create($path, $userId);
//存一次Redis
$redis->set(RedisService::SU_QRCODE_SELF_USER . $userId, $imgUrl);
}
$this->success(MSG_OK, [
'is_enterprise_certification' => $user['is_enterprise_certification'],
'is_certification' => $user['is_certification'],
'company' => $user['company'],
'username' => $user['username'],
'avatar' => $avatar,
'qrcode' => $imgUrl,
]);
}
}
这里我将二维码存到redis中,RedisService是服务类,SU_QRCODE_SELF_USER 为键值的常量。
3、前端实现
3.1、APP内置扫一扫
// 允许从相机和相册扫码
uni.scanCode({
success: function (res) {
console.log('条码类型:' + res.scanType);
console.log('条码内容:' + res.result);
}
});
// 只允许通过相机扫码
uni.scanCode({
onlyFromCamera: true,
success: function (res) {
console.log('条码类型:' + res.scanType);
console.log('条码内容:' + res.result);
}
- 我们只要识别对应的 res.result 如果是H5页面的链接就直接跳转到对应的内部APP页面即可
4、一码多用第二种方法
如果我们要处理其他端的话,可以添加一个 前端界面(需要部署到服务器)去判断和跳转,不过这样我们需要每次将这个页面部署成一个可访问的h5网站,如下流程图:
4.1、流程图
4.2、代码实现
<script>
//拆分链接后面的参数方法
let newObj = {};
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
console.log(vars);
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
newObj[pair[0]] = pair[1];
}
return (false);
}
getQueryVariable();
let u = navigator.userAgent;
if (u != null && u.contains("AlipayClient")) {
// "来自支付宝";
if (newObj.type == 1) {//跳转个人页
window.location.href = 'http://192.168.2.198:8080/#/pages/index/info/index?uid=' + newObj.uid
}
} else if(u != null && u.contains("MicroMessenger")) {
// "来自微信";
} else if(u.contains("Android")) {
// "Android移动客户端";
} else if(u.contains("iPhone")) {
// "iPhone移动客户端";
} else if(u.contains("iPad")) {
// "iPad客户端";
} else if(u.contains("Window")) {
// "PC端";
} else if(u.contains("MY_APP_iOS/1.0.0")) {
// "App端";
} else if(u.contains("miniProgram")) {
// "微信小程序端";
} else {
// "其他客户端";
}
</script>
其中 getQueryVariable 是获取拆分链接后面的参数方法,获取的参数存在对象 newObj 中。
- 相关 user-agent 对应的类型如下:
- 1、Android 系统下不同手机中微信的user-agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/WIFI Language/zh_CN
Mozilla/5.0 (Linux; Android 7.1.1; OD103 Build/NMF26F; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043632 Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN
Mozilla/5.0 (Linux; Android 6.0.1; SM919 Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043632 Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/WIFI Language/zh_CN
Mozilla/5.0 (Linux; Android 5.1.1; vivo X6S A Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043632 Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/WIFI Language/zh_CN
Mozilla/5.0 (Linux; Android 5.1; HUAWEI TAG-AL00 Build/HUAWEITAG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043622 Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN
- 2、iPhone 系统下的微信 user-agent
Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13F69 MicroMessenger/6.6.1 NetType/4G Language/zh_CN
Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_2 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C202 MicroMessenger/6.6.1 NetType/4G Language/zh_CN
Mozilla/5.0 (iPhone; CPU iPhone OS 11_1_1 like Mac OS X) AppleWebKit/604.3.5 (KHTML, like Gecko) Mobile/15B150 MicroMessenger/6.6.1 NetType/WIFI Language/zh_CN
Mozilla/5.0 (iphone x Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043632 Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/WIFI Language/zh_CN
- 3、微信内置浏览器与小程序中的 user-agent主要区别是小程序多了一个miniProgram
# 安卓系统中小程序 User Agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN miniProgram
# 安卓系统中微信内置浏览器 User Agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN
- 4、PC端的user-agent
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36
PS : 谢谢大家的观赏,有什么问题欢迎在留言区留言。