自动生成ios钱包pkpass文件"/>
nodejs服务端自动生成ios钱包pkpass文件
该博客是我在原博主发文的基础上新增了一下,因为项目用到了这个ios钱包,就研究了一下,开始还弄了挺久的,第一次写,写得不好,大神请勿见笑
1、什么是PKPass文件?
PKPass 是Apple定义的一套针对商家消费券、优惠券、火车机票等票据格式类文件。包含:图标icon、缩略图thumbnail和logo外最重要的就是pass.json、manifest.json和signature等文件的一个压缩包
2、如何制作PKPass文件?
1)、服务器端制作是比较通用的做法
这里有一个Java写的开源库:
Java版本制作PKPass的web service
2)、本地制作,按照下面的步骤:
1、去苹果开发者网站
申请Pass Type id,并且生成对应的证书(申请之前需要到钥匙串:从证书颁发机构请求证书)
2、制作pass.json
a、准备icon、logo和strip三类图片
b、 配置pass.json,这里还是强调一下passTypeIdentifier和teamIdentifier,前者就是上面在开发者中心创建的Pass Type ID(”pass.taokatao.mywallet“),后者是对应的团队标识,申请苹果开发者账号时会分配一个唯一的团队标识(可以在苹果开发者中心–查看账户信息中查看”Team ID“)。,其他信息根据实际情况配置。
{
"formatVersion": 1,
"passTypeIdentifier": "passfan.SSTPmon", //这个是ios申请的
"serialNumber": "sstpserialno0202", //序列号,这个需要随机生成,涉及到更新
"webServiceURL": "/",
"authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc", //这个地方的token我是默认的为用户登陆的token
"teamIdentifier": "L36C5JJEQ2", //ios发给你的
"locations": [
{
"longitude": -122.3748889, //位置坐标
"latitude": 37.6189722
},
{
"longitude": -122.03118,
"latitude": 37.33182
}
],
"barcode": {
"message": "d243ec6e41fa77baed63a502c7bd2d1c", //用户的id,需唯一
"format": "PKBarcodeFormatQR",
"altText": "会员详情见背面",
"messageEncoding": "iso-8859-1"
},
"organizationName": "产业园", //钱包上面展示的信息
"description": "产业园会员",
"logoText": "产业园",
"foregroundColor": "rgb(255, 255, 255)", //页面颜色
"backgroundColor": "rgb(219, 57, 68)", //会员详情页面颜色
"generic": {
"primaryFields": [ //这里面就根据用户的个人信息,自动变换
{
"key": "name",
"value": "超级管理员"
}
],
"secondaryFields": [
{
"key": "subtitle",
"label": "单位",
"value": "公司总部"
}
],
"auxiliaryFields": [
{
"key": "level",
"label": "职位",
"value": "暂无岗位"
},
{
"key": "favorite",
"label": "所属部门",
"value": "暂无部门"
}
],
"backFields": [
{
"key": "name",
"label": "姓名",
"value": "超级管理员"
},
{
"key": "gender",
"label": "性别",
"value": "女"
},
{
"key": "mobile",
"label": "手机号",
"value": "18888888888"
},
{
"key": "org",
"label": "单位名称",
"value": "公司总部"
},
{
"key": "dept",
"label": "所在部门",
"value": "暂无部门"
},
{
"key": "position",
"label": "岗位",
"value": "暂无岗位"
},
{
"key": "accountType",
"label": "账号类型",
"value": "内部用户"
}
]
}
}
3、创建manifest.json文件,可以通过”openssl sha1 [文件路径]“分别计算出所有文件的哈希值:
调用服务器脚本生成
{
"pass.json": "b017c82812e88ddbdd3d151f913e65f7c4dedcb1",
"logo.png": "e74c18f82afe65d084bec142da912829de3b81b4",
"logo@2x.png": "9b17e6a5126d553424dd9747ed006c96a09931de",
"icon.png": "e74c18f82afe65d084bec142da912829de3b81b4",
"icon@2x.png": "9b17e6a5126d553424dd9747ed006c96a09931de",
"icon@3x.png": "0b66a2a7404edfc68fca6676290e54313e7e6fd3",
"logo@3x.png": "0b66a2a7404edfc68fca6676290e54313e7e6fd3"
}
4、生成signature文件:
a.通过前面导入的Pass Type证书(Pass Type ID:pass.taokatao.mywallet)导出个人信息交换(.p12)文件并指定密码(假设密码为123123),保存成”mywallet.p12“(注意是导出证书而不是导出证书下的专用秘钥)。
b.在钥匙串中找到”Apple Worldwide Developer Relations Certification Authority“证书导出增强保密邮件(.pem),保存成”AWDRCA.pem“。
c.将.p12证书转化为.pem证书mywallet.pem(需要输入导出时设置的密码123123),输入如下命令:
openssl pkcs12 -in mywallet.p12 -clcerts -nokeys -out mywallet.pem -passin pass:123123
d.从.p12导出秘钥文件mywalletkey.pem(这里设置密码为123123)
openssl pkcs12 -in mywallet.p12 -nocerts -out mywalletkey.pem -passin pass:123123 -passout pass:123123
e.根据AWDRCA.pem、mywallet.pem、mywalletkey.pem、manifest.json生成signature文件(按照提示输入mywalletkey.pem导出时设置的密码123123):
openssl smime -binary -sign -certfile AWDRCA.pem -signer mywallet.pem -inkey mywalletkey.pem -in manifest.json -out signature -outform DER
5.将icon.png、icon@2x.png、icon@3x.png、logo.png、logo@2x.png、logo@3x.png、pass.json、manifest.json、signature压缩成pass包(这里命名为”mywallet.pkpass“)。
zip -r mywallet.pkpass manifest.json pass.json signature logo.png logo@2x.png icon.png icon@2x.png strip.png strip@2x.png
服务端调用脚本自动生成pkpass文件的接口
1、准备好这些文件,也就是上面步骤生成的和创建的文件,然后上传到服务器里面,我这边使用的是winscp,然后创建一个名为sha1.sh的脚本:openssl sha1 pass.json logo.png logo@2x.png icon.png icon@2x.png icon@3x.png logo@3x.png (因为登录用户的不同,所以用户的logo,icon,pass.json等会变化,所以需要脚本来自动生成sha1值)
2、然后再创建一个名为pkpass.sh的脚本:openssl smime -binary -sign -certfile AWDRCA.pem -signer sstp.pem -inkey sstp_key.pem -in manifest.json -out signature -outform DER -passin pass:111111 (111111为生成signature文件的密码)
zip -r ../../myhome/mypage/creatpkpass/sstp.pkpass manifest.json pass.json ./signature logo.png logo@2x.png icon.png icon@2x.png icon@3x.png logo@3x.png (这个脚本的作用就是自动生成signature文件和pkpass文件,并且指定的放到某一个目录下面)
3、服务端接口
//正则替换 把调用服务器脚本返回的sha1值改成json字符串格式
function toJson(data) {
let _data = {};
data.split("\n").filter(line => !!line).map(line => {
return line.split(/\s*=\s*/);
}).forEach(item => {
_data[item[0].match(/SHA1\((.+)\)/i)[1]] = item[1];
});
return JSON.stringify(_data);
}
//给ios钱包生成 .pkpass文件
router.post('/front/pkpass',function(req, res)
{
//获取登录用户信息
let userToken = req.loginUser.token;
let user = req.loginUser._id;
let trueName = req.loginUser.trueName || null;
let organization = commonService.isEmpty(req.loginUseranization) ? '暂无单位' : req.loginUseranization.name;
let jobTitle = commonService.isEmpty(req.loginUser.jobTitle) ? '暂无岗位' : req.loginUser.jobTitle.name;
let sex = req.loginUser.sex;
let mobile = req.loginUser.mobile;
let type = req.loginUser.type;
let query = {'_id':user};
let nowTime = commonService.getDateTime();
let serialNumber = 'sstp' + commonService.getRandomChar(6) + commonService.getTimeStamp();
// sessionService.set(mobile,serialNumber,60);
if(sex == 1){
sex = '男';
}else{
sex = '女';
}
if(type == 0){
type = '内部用户';
}else if(type == 1){
type = '园区用户';
}else{
type = '普通用户';
}
let data = fs.readFileSync('./pass.json', 'utf8');//读取json文件
let obj = JSON.parse(data);//转为json对象
userService.getItem(query,null,function(err,result){ //这个地方是版本序列号,不需要的请忽略
let serialNumber2 = result.serialNumber || null;
let oldSerialNumber = result.oldSerialNumber || [];
if(serialNumber2 != null){
oldSerialNumber.push(serialNumber2);
let fileds = {'oldSerialNumber':oldSerialNumber};
userService.update(query,fileds,function(){});
}
});
//给对象重新赋值
obj.serialNumber = serialNumber;
obj.barcode.message = userToken;
obj.generic.primaryFields[0].value = trueName;
obj.generic.secondaryFields[0].value = organization;
obj.generic.auxiliaryFields[0].value = jobTitle;
obj.generic.backFields[0].value = trueName;
obj.generic.backFields[1].value = sex;
obj.generic.backFields[2].value = mobile;
obj.generic.backFields[3].value = organization;
obj.generic.backFields[5].value = jobTitle;
obj.generic.backFields[6].value = type;
let updateFileds = {'serialNumber':serialNumber};
userService.update(query,updateFileds,function(){});
//再转为json字符串,并写回到pass.json文件
let lastData = JSON.stringify(obj);
fs.writeFileSync('./pass.json',lastData);
//调用服务器的sha1.sh脚本
process.exec('./sha1.sh',function (error, stdout, stderr) {
if (error !== null) {
console.log('exec error: ' + error);
}
var str = toJson(stdout); //调用上面的曾泽替换方法把调用脚本返回的数据转换成json格式,再写回manifest.json文件
fs.writeFileSync('./manifest.json',str);
//调用服务器脚本
process.exec('./pkpass.sh',function (error, stdout, stderr) {
if (error !== null) {
res.send(commonService.sendFail(error));
}
//把生成的pkpass文件以手机号+序列号的方式重命名,方便区分
fs.rename('../../myhome/mypage/creatpkpass/sstp.pkpass', '../../myhome/mypage/creatpkpass/' + mobile + '_' + serialNumber + '.pkpass', function(err){
if(err){
throw err;
}
res.send(commonService.sendSuccess(serialNumber));
});
});
});
});
调用了这个接口之后,会再服务器里面生成一个手机号+序列号.pkpass文件,然后把这个文件的下载链接发给ios开发人员,让ios开发人员在app用户需要生成钱包的时候调用这个接口就可以了,可以吧生成的pkpass文件下载下来发送到手机里面,如果打开能弹出下面的页面,就制作成功了
这个是我服务器生成的pkpass文件
这个是打开文件弹出来的会员钱包,信息就是该用户的基本信息
这个是会员详情页面,这样就做好了
iOS端如何加载PKPass文件?
1、Xcode新建一个工程,Bundle Identifier中命名一个App ID
2、选择目标Target,点击“Capabilities”标签,打开Wallet开关。此时需要勾选:Allow all team pass types.但是你看到的下面:“Add the wallet feature to your App ID”前面是红色的。不要紧这是因为你还没有创建App ID,看下面
3、进入Apple 开发者网站,新建一个App ID,跟第一步的App ID一致,再来看看这个红色提示就消失了,正常的对勾形式出现
4、进入目标Target,General标签,让Xcode自动为我们管理证书
5、把上面制作的PKPass文件拖到项目中
6、编码读取并显示。so easy!
#import "ViewController.h"
#import <PassKit/PassKit.h>
@interface ViewController ()<PKAddPassesViewControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
PKAddPassButton *pkAddBtn = [[PKAddPassButton alloc] initWithAddPassButtonStyle:PKAddPassButtonStyleBlack];
pkAddBtn.titleLabel.font = [UIFont systemFontOfSize:12];
pkAddBtn.frame = CGRectMake(100, 100, 220, 40);
[self.view addSubview:pkAddBtn];
[pkAddBtn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)btnClick:(PKAddPassButton *)button {
NSString *passPath=[[NSBundle mainBundle] pathForResource:@"mywallet" ofType:@"pkpass"];
NSData *passData = [[NSData alloc] initWithContentsOfFile:passPath];
NSError *error = nil;
PKPass *pass = [[PKPass alloc] initWithData:passData error:&error];
if (error) {
NSLog(@"创建Pass过程中发生错误,错误信息:%@",error.localizedDescription);
};
PKAddPassesViewController *vc = [[PKAddPassesViewController alloc] initWithPass:pass];
vc.delegate = self;
[self presentViewController:vc animated:true completion:nil];
}
-(void)addPassesViewControllerDidFinish:(PKAddPassesViewController *)controller{
NSLog(@"add pass finished.");
[self dismissViewControllerAnimated:true completion:nil];
}
---------------------
来源:CSDN
原文:
该博客是我在原博主发文的基础上新增了一下,因为项目用到了这个ios钱包,就研究了一下,开始还弄了挺久的
更多推荐
nodejs服务端自动生成ios钱包pkpass文件
发布评论