Electron应用上架Mac App Store配置说明
由于业务需要Electron应用需要打包上架到Mac App Store,特做以下记录说明
1、下载所需证书文件
证书文件需要有:
-
3rd Party Mac Developer Application
-
3rd Party Mac Developer Installer
-
Developer ID Application
-
Apple Distribution
-
provisionprofile文件(苹果开发者后台生成并导出
https://developer.apple.com/account/resources/profiles/list
) -
Mac Developer(此证书为本地测试,非必要)
将证书安装到构建mac电脑上面,在钥匙串中显示如图:
如显示证书不受信任或者无效,安装Apple全球开发者关系认证媒介中间证书AppleWWDRCA
证书链接
https://developer.apple.com/certificationauthority/AppleWWDRCA.cer
https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
https://www.apple.com/certificateauthority/AppleWWDRCAG4.cer
2、准备构建文件
2.1:创建entitlements.mas.inherit.plist文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
2.1:创建entitlements.mas.plist文件(文件中替换自己的的团队id和项目构建id,团队ID一般为证书括号中的数据(2M******),项目构建id为appid(com.***.***))
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>团队id.项目构建id</string>
</array>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
2.3、准备provisionprofile文件,苹果导出的文件
3、配置构建文件package.json文件或者build.config.js(具体信息根据项目替换)
// bundleVersion 为 bundleNumber
// target 需要包括 mas
// extendInfo 需要增加 TeamId
// asarUnpack aras 压缩时过滤.node文件,否则无法对.node文件签名
// .provisioningProfile 文件在开发者网站下载
mas: {
hardenedRuntime: false,
type: 'distribution',
category: 'public.app-category.productivity',
entitlements: 'build/mas/entitlements.mas.plist',
entitlementsInherit: 'build/mas/entitlements.mas.inherit.plist',
provisioningProfile: 'build/mas/*****.provisionprofile',
},
buildVersion: '7',
mac: {icon: 'build/icons/icon.icns',
extendInfo: {
ElectronTeamID: '2M********',
},
target: [
{
target: 'mas',
arch: 'x64',
},
],
entitlementsInherit: 'build/mas/entitlements.mas.inherit.plist',
type: 'distribution',
},
项目因为原来生成的dmg文件需要公证,已经指向了全局的env证书位置,而mas商城签名是根据provisionprofile自动调用的钥匙串中的证书,所以我另启了一个build.config.mas.js来构建mas
4、mas构建成功后添加auth.js对编译好的app进行文件权限操作(上传苹果商店可能会提示某些文件被root权限了),auth.js内容如下(具体信息根据项目替换)
var shell = require('child_process')
var path = './dist/mas/****.app'
var strRun = 'chmod -R 777 ' + path
shell.exec(strRun, function (code, stdout, stderr) {
console.log('Exit code:', code)
console.log('Program output:', stdout)
console.log('Program stderr:', stderr)
})
5、编写pkg构建文件bash.sh重新打包验签(具体信息根据项目替换)
#!/bin/bash
# 你的应用名称
APP="****"
# 要签名的应用路径
APP_PATH="./dist/mas/*****.app"
# APP_PATH="./dist/mas-arm64/*****.app"
# 生成安装包路径
RESULT_PATH="./dist/$APP.pkg"
# 开发者应用签名证书
APP_KEY="3rd Party Mac Developer Application: ****. (2M****)"
INSTALLER_KEY="3rd Party Mac Developer Installer: ***. (2M******)"
# 授权文件路径
CHILD_PLIST="./build/mas/entitlements.mas.inherit.plist"
PARENT_PLIST="./build/mas/entitlements.mas.plist"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
LIBRARY_PATH="$APP_PATH/Contents/Library"
oldIFS=$IFS
IFS=$'\n'
#递归循环验签
read_dir(){
for file in `ls $1`
do
if [ -d $1"/"$file ]
then
read_dir $1"/"$file
else
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$1/$file"
#echo $1"/"$file
fi
done
}
# 注意如果有用到 .node 文件,就需要签名。如果没有可以去掉
# codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/Resources/app.asar.unpacked/node_modules/XXX/XXX.node"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libvk_swiftshader.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper (GPU).app/Contents/MacOS/$APP Helper (GPU)"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper (Plugin).app/Contents/MacOS/$APP Helper (Plugin)"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper (Renderer).app/Contents/MacOS/$APP Helper (Renderer)"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$LIBRARY_PATH//LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/"
#ALibrariesPath="$APP_PATH/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries"
#read_dir $ALibrariesPath
AResourcesPath="$APP_PATH/Contents/Frameworks/Electron Framework.framework/Versions/A/Resources"
read_dir $AResourcesPath
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/Resources/app.asar"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/Resources/icon.icns"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/embedded.provisionprofile"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP"
codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
IFS=$oldIFS
其中codesign为shell命令,除了以上的文件验签,可能还有别的文件需要验签,根据提交到苹果商店显示的错误和邮件进行添加和修改
6、编写上传到appstore的js文件uploadappstore.js,如下(具体信息根据项目替换)
//appstore 上传
var username = '***'
var password = '***'
// var shell = require('shelljs')
var shell = require('child_process')
var path = './dist/****.pkg'
var strUploading =
'xcrun altool --upload-app --file ' +
path +
' --type osx' +
' -u ' +
username +
' -p ' +
password
// var result = shell.exec(strUploading)
// console.log(result.stdout)
console.log('start----------uploading appstore')
shell.exec(strUploading, function (code, stdout, stderr) {
console.log('Exit code:', code)
console.log('Program output:', stdout)
console.log('Program stderr:', stderr)
console.log('end----------uploaded appstore')
})
构建并上传(上传之前需要先在苹果后台构建版本号)
"build:mas": "npm run clean && npm run build:web && npm run build:appmas",
.........
.........
"build:appmas": "electron-builder -p never -c build.config.mas.js",
(一系列的构建)
"upload:appstore":"node ./auth.js && bash ./build/mas/bash.sh && node ./uploadappstore.js"
(重新验签上传)
--------------------------------------------------
成功后可以在App Store后台中看到上传的app