diff --git a/404.html b/404.html index 53c73cc..0eac348 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ -404: This page could not be found

404

This page could not be found.

\ No newline at end of file +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/_next/static/chunks/pages/docs/publish-0761daf39e4cb9bd.js b/_next/static/chunks/pages/docs/publish-0761daf39e4cb9bd.js new file mode 100644 index 0000000..0487d4a --- /dev/null +++ b/_next/static/chunks/pages/docs/publish-0761daf39e4cb9bd.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[850],{57628:function(s,e,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs/publish",function(){return n(37459)}])},37459:function(s,e,n){"use strict";n.r(e),n.d(e,{__toc:function(){return o}});var i=n(11527),r=n(5013),l=n(43196),a=n(45122);let o=[{depth:2,value:"发布原生基准版本",id:"发布原生基准版本"},{depth:3,value:"iOS",id:"ios"},{depth:3,value:"Android",id:"android"},{depth:2,value:"发布热更新版本",id:"发布热更新版本"},{depth:2,value:"测试、发布与回滚",id:"测试发布与回滚"}];function c(s){let e=Object.assign({p:"p",ol:"ol",li:"li",code:"code",a:"a",h2:"h2",h3:"h3",pre:"pre",span:"span",strong:"strong",blockquote:"blockquote"},(0,l.a)(),s.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.p,{children:"现在你的应用已经具备了检测更新的功能,下面我们来尝试发布并更新它。流程可参考下图:"}),"\n",(0,i.jsx)(a.G,{chart:'flowchart TD\n codebase["\uD83D\uDDA5️  项目代码库"]\n subgraph 发布原生基准版本\n tagNativeVersion["\uD83C\uDFF7️  (在 git 上)标记原生版本号"]\n newNativeVersion["\uD83D\uDDC2️  新的原生基准版本"]\n nativePackage["\uD83D\uDCE6  原生完整包(apk或ipa文件)"]\n tagNativeVersion--"\uD83D\uDD28  编译"-->nativePackage\n nativePackage--"⬆️  使用
pushy uploadApk/uploadIpa
命令上传"-->newNativeVersion\n end\n subgraph 发布热更新版本\n tagBundleVersion["\uD83C\uDFF7️  (在 git 上)标记热更新版本号"]\n bundlePackage["\uD83C\uDF81  js代码与资源包(ppk文件)"]\n tagBundleVersion--"\uD83D\uDD28  使用
pushy bundle
命令生成并上传"-->bundlePackage\n someNativeVersions["\uD83D\uDDC2️  一个或多个原生基准版本"]\n bundlePackage--"\uD83D\uDD87️  绑定"-->someNativeVersions\n end\n user["\uD83D\uDC68‍\uD83D\uDC69‍\uD83D\uDC67‍\uD83D\uDC66  安装有对应原生基准版本的用户"]\n codebase--"✏️  改动js代码,
或添加、更新js组件,
或添加、更新js代码中引用的图片等资源"-->发布热更新版本\n codebase--"\uD83D\uDD8A️  改动原生代码、设置,
或添加、更新原生组件,
或添加、更新原生代码中引用的图片等资源"-->发布原生基准版本\n 发布热更新版本--"\uD83D\uDCF2  推送增量热更新(diff文件)"-->user'}),"\n",(0,i.jsx)(e.p,{children:"流程总结如下:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsxs)(e.li,{children:["我们需要先打包一个原生 release 版本,在打包前请确保已集成了",(0,i.jsx)(e.code,{children:"react-native-update"}),"并在调试过程中运行正常,安卓端",(0,i.jsxs)(e.a,{href:"/docs/getting-started#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96",children:["关闭了",(0,i.jsx)(e.code,{children:"crunchPngs"}),"设置"]}),",打包说明可参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/publishing-to-app-store",children:"iOS 打包"}),"和",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/signed-apk-android",children:"android 打包"}),"。打包完成后请使用",(0,i.jsx)(e.code,{children:"pushy uploadIpa"}),"或者",(0,i.jsx)(e.code,{children:"pushy uploadApk"}),"命令来把这个安装包上传到 pushy 服务器端,以作为之后热更差量对比的基准。同时请保留好这个安装包,上架和分发给用户所使用的安装包",(0,i.jsx)(e.code,{children:"需要和服务器端完全一致"}),"。建议使用 git tag 功能来标记原生版本号(例如",(0,i.jsx)(e.code,{children:"v1.0.0"}),")。"]}),"\n",(0,i.jsxs)(e.li,{children:["然后在基准版本之上迭代业务逻辑(增删 js 代码,增删图片等静态资源),使用",(0,i.jsx)(e.code,{children:"pushy bundle"}),"命令来生成和发布热更新版本,而不需要重新打包。建议使用 git tag 功能来标记热更版本号(例如",(0,i.jsx)(e.code,{children:"v1.0.1"}),")。"]}),"\n",(0,i.jsx)(e.li,{children:"如果迭代过程中有原生方面的修改,则需要发布并上传新的原生基准版本(重复步骤 1,但需要设置不同的原生版本号)。可以只保留一个原生基准版本,也可以多版本同时维护。"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"发布原生基准版本",children:"发布原生基准版本"}),"\n",(0,i.jsx)(e.h3,{id:"ios",children:"iOS"}),"\n",(0,i.jsxs)(e.p,{children:["首先参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/running-on-device",children:"文档-在设备上运行"}),",确定你正在使用离线包。然后点击菜单。"]}),"\n",(0,i.jsxs)(e.p,{children:["按照正常的发布流程打包",(0,i.jsx)(e.code,{children:".ipa"}),"文件:"]}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"Xcode 中运行设备选真机或 Generic iOS Device"}),"\n",(0,i.jsx)(e.li,{children:"菜单中选择 Product - Archive"}),"\n",(0,i.jsxs)(e.li,{children:["Archive 完成后选择",(0,i.jsx)(e.code,{children:"Export"}),"生成.ipa 文件"]}),"\n",(0,i.jsx)(e.li,{children:"然后运行如下命令上传到 pushy 服务器以供后续版本比对之用"}),"\n"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsx)(e.code,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"uploadIpa"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:"<"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"ipa后缀文"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"件"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:">"})]})})}),"\n",(0,i.jsxs)(e.p,{children:["此 ipa 的",(0,i.jsx)(e.code,{children:"CFBundleShortVersionString"}),"字段(位于",(0,i.jsx)(e.code,{children:"ios/项目名/Info.plist"}),"中)会被记录为原生版本号",(0,i.jsx)(e.code,{children:"packageVersion"}),"。"]}),"\n",(0,i.jsxs)(e.p,{children:["随后你可以选择往 AppStore 上传这个版本(可以重新 export 并调整相关选项,但请不要重新 archive),也可以先通过",(0,i.jsx)(e.a,{href:"https://developer.apple.com/cn/testflight/",children:"Test flight"}),"或",(0,i.jsx)(e.a,{href:"https://www.pgyer.com/doc/view/build_ipa",children:"蒲公英"}),"等渠道进行真机安装测试。请注意:暂不支持通过 Xcode 直接进行热更新测试。"]}),"\n",(0,i.jsxs)(e.p,{children:["如果后续需要再次 archive 打包(例如修改原生代码或配置。如果只是修改 js 代码则不需要重新打包。),请先",(0,i.jsx)(e.strong,{children:"更改版本号"}),",并在打包完成后再次",(0,i.jsx)(e.code,{children:"uploadIpa"}),"到服务器端记录,否则后续生成的相同版本的原生包会由于",(0,i.jsxs)(e.a,{href:"faq#%E7%83%AD%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99%EF%BC%9A%E7%83%AD%E6%9B%B4%E6%96%B0%E5%B7%B2%E6%9A%82%E5%81%9C%EF%BC%8C%E5%8E%9F%E5%9B%A0%EF%BC%9Abuildtime-mismatch%E3%80%82",children:["编译时间戳不一致而",(0,i.jsx)(e.code,{children:"无法获取热更新"})]}),"。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:"注意:如果你在上传之前就运行了新的原生版本,由于服务器端没有记录,会暂停其更新数小时。可删除原先安装的 app 再重新安装以清空暂停设置。在上传之后安装的客户端不会受此影响。"}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"android",children:"Android"}),"\n",(0,i.jsxs)(e.p,{children:["首先参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/signed-apk-android",children:"文档-打包 APK"}),"设置签名,然后在 android 文件夹下运行",(0,i.jsx)(e.code,{children:"./gradlew assembleRelease"}),"或",(0,i.jsx)(e.code,{children:"./gradlew aR"}),",你就可以在",(0,i.jsx)(e.code,{children:"android/app/build/outputs/apk/release/app-release.apk"}),"中找到你的应用包。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsxs)(e.p,{children:["如果你需要使用 aab 格式(android app bundle,google 市场专用)的包,请参考这里的",(0,i.jsx)(e.a,{href:"bestpractice#%E5%A6%82%E4%BD%95%E6%94%AF%E6%8C%81-aab-%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%8E%9F%E7%94%9F%E5%8C%85",children:"做法"}),"将其转换为 apk 格式后再操作。"]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:"然后运行如下命令"}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsx)(e.code,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"uploadApk"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"android/app/build/outputs/apk/release/app-release.apk"})]})})}),"\n",(0,i.jsxs)(e.p,{children:["即可上传 apk 以供后续版本比对之用。此 apk 的",(0,i.jsx)(e.code,{children:"versionName"}),"字段(位于",(0,i.jsx)(e.code,{children:"android/app/build.gralde"}),"中)会被记录为原生版本号",(0,i.jsx)(e.code,{children:"packageVersion"}),"。"]}),"\n",(0,i.jsx)(e.p,{children:"随后你可以选择往应用市场发布这个版本,也可以先往设备上直接安装这个 apk 文件以进行测试。"}),"\n",(0,i.jsxs)(e.p,{children:["如果后续需要再次打包(例如修改原生代码或配置。如果只是修改 js 代码则不需要重新打包。),请先",(0,i.jsx)(e.strong,{children:"更改版本号"}),",并再次",(0,i.jsx)(e.code,{children:"uploadApk"}),"到服务器端记录,否则后续生成的相同版本的原生包会由于",(0,i.jsxs)(e.a,{href:"faq#%E7%83%AD%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99%EF%BC%9A%E7%83%AD%E6%9B%B4%E6%96%B0%E5%B7%B2%E6%9A%82%E5%81%9C%EF%BC%8C%E5%8E%9F%E5%9B%A0%EF%BC%9Abuildtime-mismatch%E3%80%82",children:["编译时间戳不一致而",(0,i.jsx)(e.code,{children:"无法获取热更新"})]}),"。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:"注意:如果你在上传之前就运行了新的原生版本,由于服务器端没有记录,会暂停其更新数小时。可删除原先安装的 app 再重新安装以清空暂停设置。在上传之后安装的客户端不会受此影响。"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"发布热更新版本",children:"发布热更新版本"}),"\n",(0,i.jsxs)(e.p,{children:["你可以尝试修改一行代码(譬如将版本一修改为版本二),然后使用",(0,i.jsx)(e.code,{children:"pushy bundle --platform "}),"命令来生成新的热更新版本。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"bash","data-theme":"default",children:[(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"bundle"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"--platform"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"android"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Bundling"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"with"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"React"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"Native"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"version:"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-constant)"},children:"0.22"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:".2"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:"<"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"各种进度输出"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:">"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Bundled"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"saved"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"to:"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"build/output/android.1459850548545.ppk"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Would"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"you"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"like"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"to"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"publish"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"it?"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"("}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Y/N"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:")"})]})]})}),"\n",(0,i.jsxs)(e.p,{children:["如果想要立即上传,此时输入 Y。当然,你也可以在将来使用",(0,i.jsx)(e.code,{children:"pushy publish --platform android build/output/android.1459850548545.ppk"}),"来上传刚才打包好的热更新包。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"text","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"text","data-theme":"default",children:[(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" Uploading [========================================================] 100% 0.0s"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Enter version name: <输入热更新版本名字,如1.0.0-rc>"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Enter description: <输入热更新版本描述>"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:'Enter meta info: {"ok":1}'})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Ok."})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Would you like to bind packages to this version?(Y/N)"})})]})}),"\n",(0,i.jsx)(e.p,{children:"此时版本已经提交到 pushy 服务,但用户暂时看不到此更新,你需要先将特定的原生包版本绑定到此热更新版本上。"}),"\n",(0,i.jsxs)(e.p,{children:["此时输入 Y 立即绑定,你也可以在将来使用",(0,i.jsx)(e.code,{children:"pushy update --platform "}),"来对已上传的热更包和原生包进行绑定。除此以外,你还可以在网页端操作,简单的将对应的原生包版本拖到需要的热更新版本下即可。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"text","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"text","data-theme":"default",children:[(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"┌────────────┬──────────────────────────────────────┐"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ Package Id │ Version │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"├────────────┼──────────────────────────────────────┤"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ 46272 │ 2.0(normal) │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"├────────────┼──────────────────────────────────────┤"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ 45577 │ 1.0(normal) │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"└────────────┴──────────────────────────────────────┘"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"共 2 个包"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"输入原生包 id: 46272"})})]})}),"\n",(0,i.jsx)(e.p,{children:"版本绑定完毕后,服务器会在几秒内生成差量补丁,客户端就可以获取到更新了。"}),"\n",(0,i.jsxs)(e.p,{children:["后续要继续发布新的热更新,只需反复执行",(0,i.jsx)(e.code,{children:"pushy bundle"}),"命令即可,不需要重新打包。"]}),"\n",(0,i.jsx)(e.p,{children:"恭喜你,至此为止,你已经完成了植入代码热更新的全部工作。"}),"\n",(0,i.jsx)(e.h2,{id:"测试发布与回滚",children:"测试、发布与回滚"}),"\n",(0,i.jsxs)(e.p,{children:["我们强烈建议您先发布一个",(0,i.jsx)(e.strong,{children:"测试包"}),",再发布一个除了版本号以外均完全相同的",(0,i.jsx)(e.strong,{children:"正式包"}),"。"]}),"\n",(0,i.jsxs)(e.p,{children:["例如,假设我们有一个正式包,版本为",(0,i.jsx)(e.code,{children:"1.6.0"}),",那么可以修改版本号重新打包一个",(0,i.jsx)(e.code,{children:"1001.6.0"}),",以一个明显不太正常的版本号来标识它是一个测试版本,同时后几位相同,可以表明它和某个正式版本存在关联(内容/依赖一致)。"]}),"\n",(0,i.jsxs)(e.p,{children:["在每次往发布包发起热更新之前,先对",(0,i.jsx)(e.strong,{children:"测试包"}),(0,i.jsx)(e.code,{children:"1001.6.0"}),"进行更新操作,基本测试通过之后,再在网页后台上将热更包重新绑定到",(0,i.jsx)(e.strong,{children:"正式包"}),(0,i.jsx)(e.code,{children:"1.6.0"}),"上。如果在测试包中发现了重大问题,你就可以先进行修复,更新测试确认通过后再部署到正式线上环境。这样,可以最大程度的避免发生线上事故。"]}),"\n",(0,i.jsx)(e.p,{children:"万一确实发生线上事故需要回滚的话,首先利用版本控制系统回滚代码到正常的状态,然后重新生成热更包并推送即可。"})]})}e.default=(0,r.j)({MDXContent:function(){let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:e}=Object.assign({},(0,l.a)(),s.components);return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(c,{...s})}):c(s)},pageOpts:{filePath:"pages/docs/publish.md",route:"/docs/publish",frontMatter:{order:2,title:"发布热更新",type:"快速入门"},title:"发布热更新",headings:o},pageNextRoute:"/docs/publish"})}},function(s){s.O(0,[386,13,807,774,888,179],function(){return s(s.s=57628)}),_N_E=s.O()}]); \ No newline at end of file diff --git a/_next/static/chunks/pages/docs/publish-18497e8e8ec946cc.js b/_next/static/chunks/pages/docs/publish-18497e8e8ec946cc.js deleted file mode 100644 index 5fb694e..0000000 --- a/_next/static/chunks/pages/docs/publish-18497e8e8ec946cc.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[850],{57628:function(s,e,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs/publish",function(){return n(37459)}])},37459:function(s,e,n){"use strict";n.r(e),n.d(e,{__toc:function(){return o}});var i=n(11527),r=n(5013),l=n(43196),a=n(45122);let o=[{depth:2,value:"发布原生基准版本",id:"发布原生基准版本"},{depth:3,value:"iOS",id:"ios"},{depth:3,value:"Android",id:"android"},{depth:2,value:"发布热更新版本",id:"发布热更新版本"},{depth:2,value:"测试、发布与回滚",id:"测试发布与回滚"}];function c(s){let e=Object.assign({p:"p",ol:"ol",li:"li",code:"code",a:"a",h2:"h2",h3:"h3",pre:"pre",span:"span",strong:"strong",blockquote:"blockquote"},(0,l.a)(),s.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.p,{children:"现在你的应用已经具备了检测更新的功能,下面我们来尝试发布并更新它。流程可参考下图:"}),"\n",(0,i.jsx)(a.G,{chart:'flowchart TD\n codebase["\uD83D\uDDA5️  项目代码库"]\n subgraph 发布原生基准版本\n tagNativeVersion["\uD83C\uDFF7️  (在 git 上)标记原生版本号"]\n newNativeVersion["\uD83D\uDDC2️  新的原生基准版本"]\n nativePackage["\uD83D\uDCE6  原生完整包(apk或ipa文件)"]\n tagNativeVersion--"\uD83D\uDD28  编译"-->nativePackage\n nativePackage--"⬆️  使用
pushy uploadApk/uploadIpa
命令上传"-->newNativeVersion\n end\n subgraph 发布热更新版本\n tagBundleVersion["\uD83C\uDFF7️  (在 git 上)标记热更新版本号"]\n bundlePackage["\uD83C\uDF81  js代码与资源包(ppk文件)"]\n tagBundleVersion--"\uD83D\uDD28  使用
pushy bundle
命令生成并上传"-->bundlePackage\n someNativeVersions["\uD83D\uDDC2️  一个或多个原生基准版本"]\n bundlePackage--"\uD83D\uDD87️  绑定"-->someNativeVersions\n end\n user["\uD83D\uDC68‍\uD83D\uDC69‍\uD83D\uDC67‍\uD83D\uDC66  安装有对应原生基准版本的用户"]\n codebase--"✏️  改动js代码,
或添加、更新js组件,
或添加、更新js代码中引用的图片等资源"-->发布热更新版本\n codebase--"\uD83D\uDD8A️  改动原生代码、设置,
或添加、更新原生组件,
或添加、更新原生代码中引用的图片等资源"-->发布原生基准版本\n 发布热更新版本--"\uD83D\uDCF2  推送增量热更新(diff文件)"-->user'}),"\n",(0,i.jsx)(e.p,{children:"流程总结如下:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsxs)(e.li,{children:["我们需要先打包一个原生 release 版本,在打包前请确保已集成了",(0,i.jsx)(e.code,{children:"react-native-update"}),"并在调试过程中运行正常,安卓端",(0,i.jsxs)(e.a,{href:"/docs/getting-started#%E7%A6%81%E7%94%A8-android-%E7%9A%84-crunch-%E4%BC%98%E5%8C%96",children:["关闭了",(0,i.jsx)(e.code,{children:"crunchPngs"}),"设置"]}),",打包说明可参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/publishing-to-app-store",children:"iOS 打包"}),"和",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/signed-apk-android",children:"android 打包"}),"。打包完成后请使用",(0,i.jsx)(e.code,{children:"pushy uploadIpa"}),"或者",(0,i.jsx)(e.code,{children:"pushy uploadApk"}),"命令来把这个安装包上传到 pushy 服务器端,以作为之后热更差量对比的基准。同时请保留好这个安装包,上架和分发给用户所使用的安装包",(0,i.jsx)(e.code,{children:"需要和服务器端完全一致"}),"。建议使用 git tag 功能来标记原生版本号(例如",(0,i.jsx)(e.code,{children:"v1.0.0"}),")。"]}),"\n",(0,i.jsxs)(e.li,{children:["然后在基准版本之上迭代业务逻辑(增删 js 代码,增删图片等静态资源),使用",(0,i.jsx)(e.code,{children:"pushy bundle"}),"命令来生成和发布热更新版本,而不需要重新打包。建议使用 git tag 功能来标记热更版本号(例如",(0,i.jsx)(e.code,{children:"v1.0.1"}),")。"]}),"\n",(0,i.jsx)(e.li,{children:"如果迭代过程中有原生方面的修改,则需要发布并上传新的原生基准版本(重复步骤 1,但需要设置不同的原生版本号)。可以只保留一个原生基准版本,也可以多版本同时维护。"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"发布原生基准版本",children:"发布原生基准版本"}),"\n",(0,i.jsx)(e.h3,{id:"ios",children:"iOS"}),"\n",(0,i.jsxs)(e.p,{children:["首先参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/running-on-device",children:"文档-在设备上运行"}),",确定你正在使用离线包。然后点击菜单。"]}),"\n",(0,i.jsxs)(e.p,{children:["按照正常的发布流程打包",(0,i.jsx)(e.code,{children:".ipa"}),"文件:"]}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsx)(e.li,{children:"Xcode 中运行设备选真机或 Generic iOS Device"}),"\n",(0,i.jsx)(e.li,{children:"菜单中选择 Product - Archive"}),"\n",(0,i.jsxs)(e.li,{children:["Archive 完成后选择",(0,i.jsx)(e.code,{children:"Export"}),"生成.ipa 文件"]}),"\n",(0,i.jsx)(e.li,{children:"然后运行如下命令上传到 pushy 服务器以供后续版本比对之用"}),"\n"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsx)(e.code,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"uploadIpa"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:"<"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"ipa后缀文"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"件"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:">"})]})})}),"\n",(0,i.jsxs)(e.p,{children:["此 ipa 的",(0,i.jsx)(e.code,{children:"CFBundleShortVersionString"}),"字段(位于",(0,i.jsx)(e.code,{children:"ios/项目名/Info.plist"}),"中)会被记录为原生版本号",(0,i.jsx)(e.code,{children:"packageVersion"}),"。"]}),"\n",(0,i.jsxs)(e.p,{children:["随后你可以选择往 AppStore 上传这个版本(可以重新 export 并调整相关选项,但请不要重新 archive),也可以先通过",(0,i.jsx)(e.a,{href:"https://developer.apple.com/cn/testflight/",children:"Test flight"}),"或",(0,i.jsx)(e.a,{href:"https://www.pgyer.com/doc/view/build_ipa",children:"蒲公英"}),"等渠道进行真机安装测试。请注意:暂不支持通过 Xcode 直接进行热更新测试。"]}),"\n",(0,i.jsxs)(e.p,{children:["如果后续需要再次 archive 打包(例如修改原生代码或配置。如果只是修改 js 代码则不需要重新打包。),请先",(0,i.jsx)(e.strong,{children:"更改版本号"}),",并在打包完成后再次",(0,i.jsx)(e.code,{children:"uploadIpa"}),"到服务器端记录,否则后续生成的相同版本的原生包会由于",(0,i.jsxs)(e.a,{href:"faq#%E7%83%AD%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99%EF%BC%9A%E7%83%AD%E6%9B%B4%E6%96%B0%E5%B7%B2%E6%9A%82%E5%81%9C%EF%BC%8C%E5%8E%9F%E5%9B%A0%EF%BC%9Abuildtime-mismatch%E3%80%82",children:["编译时间戳不一致而",(0,i.jsx)(e.code,{children:"无法获取热更新"})]}),"。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:"注意:如果你在上传之前就运行了新的原生版本,由于服务器端没有记录,会暂停其更新数小时。可删除原先安装的 app 再重新安装以清空暂停设置。在上传之后安装的客户端不会受此影响。"}),"\n"]}),"\n",(0,i.jsx)(e.h3,{id:"android",children:"Android"}),"\n",(0,i.jsxs)(e.p,{children:["首先参考",(0,i.jsx)(e.a,{href:"https://reactnative.cn/docs/signed-apk-android",children:"文档-打包 APK"}),"设置签名,然后在 android 文件夹下运行",(0,i.jsx)(e.code,{children:"./gradlew assembleRelease"}),"或",(0,i.jsx)(e.code,{children:"./gradlew aR"}),",你就可以在",(0,i.jsx)(e.code,{children:"android/app/build/outputs/apk/release/app-release.apk"}),"中找到你的应用包。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsxs)(e.p,{children:["如果你需要使用 aab 格式(android app bundle,google 市场专用)的包,请参考这里的",(0,i.jsx)(e.a,{href:"bestpractice#%E5%A6%82%E4%BD%95%E6%94%AF%E6%8C%81-aab-%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%8E%9F%E7%94%9F%E5%8C%85%EF%BC%9F",children:"做法"}),"将其转换为 apk 格式后再操作。"]}),"\n"]}),"\n",(0,i.jsx)(e.p,{children:"然后运行如下命令"}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsx)(e.code,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"uploadApk"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"android/app/build/outputs/apk/release/app-release.apk"})]})})}),"\n",(0,i.jsxs)(e.p,{children:["即可上传 apk 以供后续版本比对之用。此 apk 的",(0,i.jsx)(e.code,{children:"versionName"}),"字段(位于",(0,i.jsx)(e.code,{children:"android/app/build.gralde"}),"中)会被记录为原生版本号",(0,i.jsx)(e.code,{children:"packageVersion"}),"。"]}),"\n",(0,i.jsx)(e.p,{children:"随后你可以选择往应用市场发布这个版本,也可以先往设备上直接安装这个 apk 文件以进行测试。"}),"\n",(0,i.jsxs)(e.p,{children:["如果后续需要再次打包(例如修改原生代码或配置。如果只是修改 js 代码则不需要重新打包。),请先",(0,i.jsx)(e.strong,{children:"更改版本号"}),",并再次",(0,i.jsx)(e.code,{children:"uploadApk"}),"到服务器端记录,否则后续生成的相同版本的原生包会由于",(0,i.jsxs)(e.a,{href:"faq#%E7%83%AD%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99%EF%BC%9A%E7%83%AD%E6%9B%B4%E6%96%B0%E5%B7%B2%E6%9A%82%E5%81%9C%EF%BC%8C%E5%8E%9F%E5%9B%A0%EF%BC%9Abuildtime-mismatch%E3%80%82",children:["编译时间戳不一致而",(0,i.jsx)(e.code,{children:"无法获取热更新"})]}),"。"]}),"\n",(0,i.jsxs)(e.blockquote,{children:["\n",(0,i.jsx)(e.p,{children:"注意:如果你在上传之前就运行了新的原生版本,由于服务器端没有记录,会暂停其更新数小时。可删除原先安装的 app 再重新安装以清空暂停设置。在上传之后安装的客户端不会受此影响。"}),"\n"]}),"\n",(0,i.jsx)(e.h2,{id:"发布热更新版本",children:"发布热更新版本"}),"\n",(0,i.jsxs)(e.p,{children:["你可以尝试修改一行代码(譬如将版本一修改为版本二),然后使用",(0,i.jsx)(e.code,{children:"pushy bundle --platform "}),"命令来生成新的热更新版本。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"bash","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"bash","data-theme":"default",children:[(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"$"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"pushy"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"bundle"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"--platform"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"android"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Bundling"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"with"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"React"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"Native"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"version:"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-constant)"},children:"0.22"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:".2"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:"<"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"各种进度输出"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-keyword)"},children:">"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Bundled"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"saved"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"to:"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"build/output/android.1459850548545.ppk"})]}),"\n",(0,i.jsxs)(e.span,{className:"line",children:[(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Would"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"you"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"like"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"to"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"publish"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" "}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-string)"},children:"it?"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"("}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-token-function)"},children:"Y/N"}),(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:")"})]})]})}),"\n",(0,i.jsxs)(e.p,{children:["如果想要立即上传,此时输入 Y。当然,你也可以在将来使用",(0,i.jsx)(e.code,{children:"pushy publish --platform android build/output/android.1459850548545.ppk"}),"来上传刚才打包好的热更新包。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"text","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"text","data-theme":"default",children:[(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:" Uploading [========================================================] 100% 0.0s"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Enter version name: <输入热更新版本名字,如1.0.0-rc>"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Enter description: <输入热更新版本描述>"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:'Enter meta info: {"ok":1}'})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Ok."})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"Would you like to bind packages to this version?(Y/N)"})})]})}),"\n",(0,i.jsx)(e.p,{children:"此时版本已经提交到 pushy 服务,但用户暂时看不到此更新,你需要先将特定的原生包版本绑定到此热更新版本上。"}),"\n",(0,i.jsxs)(e.p,{children:["此时输入 Y 立即绑定,你也可以在将来使用",(0,i.jsx)(e.code,{children:"pushy update --platform "}),"来对已上传的热更包和原生包进行绑定。除此以外,你还可以在网页端操作,简单的将对应的原生包版本拖到需要的热更新版本下即可。"]}),"\n",(0,i.jsx)(e.pre,{"data-language":"text","data-theme":"default",children:(0,i.jsxs)(e.code,{"data-language":"text","data-theme":"default",children:[(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"┌────────────┬──────────────────────────────────────┐"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ Package Id │ Version │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"├────────────┼──────────────────────────────────────┤"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ 46272 │ 2.0(normal) │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"├────────────┼──────────────────────────────────────┤"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"│ 45577 │ 1.0(normal) │"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"└────────────┴──────────────────────────────────────┘"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"共 2 个包"})}),"\n",(0,i.jsx)(e.span,{className:"line",children:(0,i.jsx)(e.span,{style:{color:"var(--shiki-color-text)"},children:"输入原生包 id: 46272"})})]})}),"\n",(0,i.jsx)(e.p,{children:"版本绑定完毕后,服务器会在几秒内生成差量补丁,客户端就可以获取到更新了。"}),"\n",(0,i.jsxs)(e.p,{children:["后续要继续发布新的热更新,只需反复执行",(0,i.jsx)(e.code,{children:"pushy bundle"}),"命令即可,不需要重新打包。"]}),"\n",(0,i.jsx)(e.p,{children:"恭喜你,至此为止,你已经完成了植入代码热更新的全部工作。"}),"\n",(0,i.jsx)(e.h2,{id:"测试发布与回滚",children:"测试、发布与回滚"}),"\n",(0,i.jsxs)(e.p,{children:["我们强烈建议您先发布一个",(0,i.jsx)(e.strong,{children:"测试包"}),",再发布一个除了版本号以外均完全相同的",(0,i.jsx)(e.strong,{children:"正式包"}),"。"]}),"\n",(0,i.jsxs)(e.p,{children:["例如,假设我们有一个正式包,版本为",(0,i.jsx)(e.code,{children:"1.6.0"}),",那么可以修改版本号重新打包一个",(0,i.jsx)(e.code,{children:"1001.6.0"}),",以一个明显不太正常的版本号来标识它是一个测试版本,同时后几位相同,可以表明它和某个正式版本存在关联(内容/依赖一致)。"]}),"\n",(0,i.jsxs)(e.p,{children:["在每次往发布包发起热更新之前,先对",(0,i.jsx)(e.strong,{children:"测试包"}),(0,i.jsx)(e.code,{children:"1001.6.0"}),"进行更新操作,基本测试通过之后,再在网页后台上将热更包重新绑定到",(0,i.jsx)(e.strong,{children:"正式包"}),(0,i.jsx)(e.code,{children:"1.6.0"}),"上。如果在测试包中发现了重大问题,你就可以先进行修复,更新测试确认通过后再部署到正式线上环境。这样,可以最大程度的避免发生线上事故。"]}),"\n",(0,i.jsx)(e.p,{children:"万一确实发生线上事故需要回滚的话,首先利用版本控制系统回滚代码到正常的状态,然后重新生成热更包并推送即可。"})]})}e.default=(0,r.j)({MDXContent:function(){let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:e}=Object.assign({},(0,l.a)(),s.components);return e?(0,i.jsx)(e,{...s,children:(0,i.jsx)(c,{...s})}):c(s)},pageOpts:{filePath:"pages/docs/publish.md",route:"/docs/publish",frontMatter:{order:2,title:"发布热更新",type:"快速入门"},title:"发布热更新",headings:o},pageNextRoute:"/docs/publish"})}},function(s){s.O(0,[386,13,807,774,888,179],function(){return s(s.s=57628)}),_N_E=s.O()}]); \ No newline at end of file diff --git a/_next/static/oFizIWZgxhEFq0IDsRuxS/_buildManifest.js b/_next/static/hWOfHxb6NozCOwDHFcgaB/_buildManifest.js similarity index 95% rename from _next/static/oFizIWZgxhEFq0IDsRuxS/_buildManifest.js rename to _next/static/hWOfHxb6NozCOwDHFcgaB/_buildManifest.js index 18d829a..cd2b8c0 100644 --- a/_next/static/oFizIWZgxhEFq0IDsRuxS/_buildManifest.js +++ b/_next/static/hWOfHxb6NozCOwDHFcgaB/_buildManifest.js @@ -1 +1 @@ -self.__BUILD_MANIFEST=function(s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,"static/chunks/751-e6b1b04852480656.js","static/chunks/pages/index-eee58a1770b22ca6.js"],"/_error":["static/chunks/pages/_error-c2b109bd2149f9d1.js"],"/docs/api":[s,"static/chunks/pages/docs/api-5b87e137f7669fca.js"],"/docs/bestpractice":[s,"static/chunks/pages/docs/bestpractice-f667562c9120da54.js"],"/docs/changelog":[s,"static/chunks/pages/docs/changelog-a44050c445cef539.js"],"/docs/cli":[s,"static/chunks/pages/docs/cli-50d0eb6dbcc3892e.js"],"/docs/faq":[s,"static/chunks/pages/docs/faq-3feb5012af493fc9.js"],"/docs/getting-started":[s,"static/chunks/pages/docs/getting-started-3106b0541d43cfac.js"],"/docs/integration":[s,"static/chunks/pages/docs/integration-871e3e6e921dfefc.js"],"/docs/publish":["static/chunks/42a66924-d3638db00b3ad4e8.js",s,"static/chunks/807-16fc744826449e1e.js","static/chunks/pages/docs/publish-18497e8e8ec946cc.js"],"/pricing":[s,"static/chunks/467-604214b68d2fd0ac.js","static/chunks/pages/pricing-32cdce4af104312c.js"],sortedPages:["/","/_app","/_error","/docs/api","/docs/bestpractice","/docs/changelog","/docs/cli","/docs/faq","/docs/getting-started","/docs/integration","/docs/publish","/pricing"]}}("static/chunks/13-b2ead5f8cb5483ca.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file +self.__BUILD_MANIFEST=function(s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,"static/chunks/751-e6b1b04852480656.js","static/chunks/pages/index-eee58a1770b22ca6.js"],"/_error":["static/chunks/pages/_error-c2b109bd2149f9d1.js"],"/docs/api":[s,"static/chunks/pages/docs/api-5b87e137f7669fca.js"],"/docs/bestpractice":[s,"static/chunks/pages/docs/bestpractice-f667562c9120da54.js"],"/docs/changelog":[s,"static/chunks/pages/docs/changelog-a44050c445cef539.js"],"/docs/cli":[s,"static/chunks/pages/docs/cli-50d0eb6dbcc3892e.js"],"/docs/faq":[s,"static/chunks/pages/docs/faq-3feb5012af493fc9.js"],"/docs/getting-started":[s,"static/chunks/pages/docs/getting-started-3106b0541d43cfac.js"],"/docs/integration":[s,"static/chunks/pages/docs/integration-871e3e6e921dfefc.js"],"/docs/publish":["static/chunks/42a66924-d3638db00b3ad4e8.js",s,"static/chunks/807-16fc744826449e1e.js","static/chunks/pages/docs/publish-0761daf39e4cb9bd.js"],"/pricing":[s,"static/chunks/467-604214b68d2fd0ac.js","static/chunks/pages/pricing-32cdce4af104312c.js"],sortedPages:["/","/_app","/_error","/docs/api","/docs/bestpractice","/docs/changelog","/docs/cli","/docs/faq","/docs/getting-started","/docs/integration","/docs/publish","/pricing"]}}("static/chunks/13-b2ead5f8cb5483ca.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB(); \ No newline at end of file diff --git a/_next/static/oFizIWZgxhEFq0IDsRuxS/_ssgManifest.js b/_next/static/hWOfHxb6NozCOwDHFcgaB/_ssgManifest.js similarity index 100% rename from _next/static/oFizIWZgxhEFq0IDsRuxS/_ssgManifest.js rename to _next/static/hWOfHxb6NozCOwDHFcgaB/_ssgManifest.js diff --git a/docs/api.html b/docs/api.html index 47c5da1..d7a269b 100644 --- a/docs/api.html +++ b/docs/api.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
API参考

JavaScript 常量

+
\ No newline at end of file +UpdateContext.setCustomInstanceManager(mReactInstanceManager);
\ No newline at end of file diff --git a/docs/bestpractice.html b/docs/bestpractice.html index 50861f3..52179fe 100644 --- a/docs/bestpractice.html +++ b/docs/bestpractice.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
场景实践

优化原生和热更包体积

+
文档
场景实践

优化原生和热更包体积

iOS 原生包优化(ipa)

对于同一份 archive(其版本号、编译时间和内置 bundle 已固定,不会受导出方式所影响),可以用不同选项多次导出 ipa,选择其中最小的上传到 pushy 服务器作为热更基准包。

bitcode

@@ -105,4 +105,4 @@

// 否则还是走之前的询问流程 // Alert.alert('提示', '检查到新的版本....... }

-

又比如,可能某个版本包含一些重要的公告内容,所以还可以在上面插入一个公告字段等等。如何使用元信息,完全取决于您的想象力!

\ No newline at end of file +

又比如,可能某个版本包含一些重要的公告内容,所以还可以在上面插入一个公告字段等等。如何使用元信息,完全取决于您的想象力!

\ No newline at end of file diff --git a/docs/changelog.html b/docs/changelog.html index 5ee910c..a05f994 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
更新日志

9.0.0(2023-09-02)

+
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/cli.html b/docs/cli.html index 78e9561..feaf602 100644 --- a/docs/cli.html +++ b/docs/cli.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
命令行工具

安装

+
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/faq.html b/docs/faq.html index d4d03f4..1aec967 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
常见问题

如果本页面没能回答您的疑问,您可以去issues 区 (opens in a new tab)或 QQ 群 729013783 提问,或给我们发邮件

+
文档
常见问题

如果本页面没能回答您的疑问,您可以去issues 区 (opens in a new tab)或 QQ 群 729013783 提问,或给我们发邮件

业务问题

热更新究竟能否上架?

您可能听说过各种说法,但大量实践表明,热更新目前能够顺利上架 AppStore 和其他各种应用市场。唯一需要注意的是,在审核期间请不要发布热更新,不要让审核人员看到各种更新相关的提示和弹窗,即可顺利通过。

@@ -103,4 +103,4 @@

可以的。请对照价格表,将对应版本的款项转账至:

公司名称武汉青罗网络科技有限公司
开户行名称浙江网商银行
账号8888888048825564

转账完成后请截图发送至 hi@charmlot.com ,并写明注册邮箱,我们将在一个工作日内开通对应服务。

-

\ No newline at end of file +
\ No newline at end of file diff --git a/docs/getting-started.html b/docs/getting-started.html index 944a1ed..d25467d 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
安装配置

首先你应该有一个基于 React Native 开发的应用,我们把具有 package.json 的目录叫做你的应用根目录。 +

文档
安装配置

首先你应该有一个基于 React Native 开发的应用,我们把具有 package.json 的目录叫做你的应用根目录。 如果你还没有初始化应用,请参阅开始使用 React Native (opens in a new tab)

我们假设你已经拥有了开发 React Native 应用的一切环境,包括Node.jsXCodeAndroid SDK等等。

安装

在你的项目根目录下运行以下命令:

# 先全局安装命令行工具,每台电脑只用装一次
@@ -146,4 +146,4 @@
         "appId": 2,
         "appKey": "<一串随机字符串>"
     }
-}

你可以安全的把update.json上传到 Git 等 CVS 系统上,与你的团队共享这个文件,它不包含任何敏感信息。当然,他们在使用任何功能之前,都必须首先输入pushy login进行登录。

至此应用的创建/选择就已经成功了。下一步,你需要给代码添加相应的功能,请参阅代码集成

\ No newline at end of file +}

你可以安全的把update.json上传到 Git 等 CVS 系统上,与你的团队共享这个文件,它不包含任何敏感信息。当然,他们在使用任何功能之前,都必须首先输入pushy login进行登录。

至此应用的创建/选择就已经成功了。下一步,你需要给代码添加相应的功能,请参阅代码集成

\ No newline at end of file diff --git a/docs/integration.html b/docs/integration.html index 830ca7e..3cd92ff 100644 --- a/docs/integration.html +++ b/docs/integration.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
代码集成

安装配置完成后,确定应用编译顺利通过,下面我们来进行代码集成。

+
文档
代码集成

安装配置完成后,确定应用编译顺利通过,下面我们来进行代码集成。

极简快速集成

我们从 v8.x 版本开始提供极简的三行式集成(老版本只能使用自定义集成方式):

import { Platform } from "react-native";
@@ -256,4 +256,4 @@ 

marginBottom: 5, }, });

-

现在,你的应用已经可以通过 pushy 服务检查版本并进行更新了。下一步,你可以开始尝试发布应用包和版本,请参阅发布热更新

\ No newline at end of file +

现在,你的应用已经可以通过 pushy 服务检查版本并进行更新了。下一步,你可以开始尝试发布应用包和版本,请参阅发布热更新

\ No newline at end of file diff --git a/docs/publish.html b/docs/publish.html index 0bbb65b..f8b8cab 100644 --- a/docs/publish.html +++ b/docs/publish.html @@ -11,7 +11,7 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -
文档
发布流程

现在你的应用已经具备了检测更新的功能,下面我们来尝试发布并更新它。流程可参考下图:

+
文档
发布流程

现在你的应用已经具备了检测更新的功能,下面我们来尝试发布并更新它。流程可参考下图:

流程总结如下:

    @@ -39,7 +39,7 @@

    Android

    首先参考文档-打包 APK (opens in a new tab)设置签名,然后在 android 文件夹下运行./gradlew assembleRelease./gradlew aR,你就可以在android/app/build/outputs/apk/release/app-release.apk中找到你的应用包。

    -

    如果你需要使用 aab 格式(android app bundle,google 市场专用)的包,请参考这里的做法将其转换为 apk 格式后再操作。

    +

    如果你需要使用 aab 格式(android app bundle,google 市场专用)的包,请参考这里的做法将其转换为 apk 格式后再操作。

    然后运行如下命令

    $ pushy uploadApk android/app/build/outputs/apk/release/app-release.apk
    @@ -81,4 +81,4 @@

    我们强烈建议您先发布一个测试包,再发布一个除了版本号以外均完全相同的正式包

    例如,假设我们有一个正式包,版本为1.6.0,那么可以修改版本号重新打包一个1001.6.0,以一个明显不太正常的版本号来标识它是一个测试版本,同时后几位相同,可以表明它和某个正式版本存在关联(内容/依赖一致)。

    在每次往发布包发起热更新之前,先对测试包1001.6.0进行更新操作,基本测试通过之后,再在网页后台上将热更包重新绑定到正式包1.6.0上。如果在测试包中发现了重大问题,你就可以先进行修复,更新测试确认通过后再部署到正式线上环境。这样,可以最大程度的避免发生线上事故。

    -

    万一确实发生线上事故需要回滚的话,首先利用版本控制系统回滚代码到正常的状态,然后重新生成热更包并推送即可。

\ No newline at end of file +

万一确实发生线上事故需要回滚的话,首先利用版本控制系统回滚代码到正常的状态,然后重新生成热更包并推送即可。

\ No newline at end of file diff --git a/index.html b/index.html index c6532de..b67931d 100644 --- a/index.html +++ b/index.html @@ -11,4 +11,4 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -

他们选择了 Pushy

网易游戏
蓝月亮
华中师范大学
娇兰佳人
平安不动产
友车科技
诺安基金
锐捷网络
航天信息
天津公交
Feature

为什么选择 Pushy

  • img

    增量更新

    基于 bsdiff/hdiff 算法创建

    kb 级别超小更新包

  • img

    快捷发布

    命令行工具 & 网页双端管理

    支持CI部署

  • img

    极速下载

    基于阿里云高速CDN分发

    全国范围秒速更新

  • img

    稳定可靠

    自带崩溃回滚机制

    安全可靠

  • img

    灵活扩展

    开放定制元信息

    提供灵活自由的更新策略

  • img

    技术支持

    遇到技术问题?

    工作时间段内小时级别响应

    Icons made by Swifticons from www.flaticon.com

    Let’s Pushy

    # 安装
    $ npm i -g react-native-update-cli
    $ npm i react-native-update && cd ios && pod install

    # 上传原生基础包
    $ pushy uploadIpa yourApp.ipa
    $ pushy uploadApk yourApp.apk

    # 生成并上传热更包
    $ pushy bundle --platform android
    $ pushy bundle --platform ios
    查看文档
    \ No newline at end of file +

    他们选择了 Pushy

    网易游戏
    蓝月亮
    华中师范大学
    娇兰佳人
    平安不动产
    友车科技
    诺安基金
    锐捷网络
    航天信息
    天津公交
    Feature

    为什么选择 Pushy

    • img

      增量更新

      基于 bsdiff/hdiff 算法创建

      kb 级别超小更新包

    • img

      快捷发布

      命令行工具 & 网页双端管理

      支持CI部署

    • img

      极速下载

      基于阿里云高速CDN分发

      全国范围秒速更新

    • img

      稳定可靠

      自带崩溃回滚机制

      安全可靠

    • img

      灵活扩展

      开放定制元信息

      提供灵活自由的更新策略

    • img

      技术支持

      遇到技术问题?

      工作时间段内小时级别响应

      Icons made by Swifticons from www.flaticon.com

      Let’s Pushy

      # 安装
      $ npm i -g react-native-update-cli
      $ npm i react-native-update && cd ios && pod install

      # 上传原生基础包
      $ pushy uploadIpa yourApp.ipa
      $ pushy uploadApk yourApp.apk

      # 生成并上传热更包
      $ pushy bundle --platform android
      $ pushy bundle --platform ios
      查看文档
      \ No newline at end of file diff --git a/pricing.html b/pricing.html index f148a4a..5ccb37e 100644 --- a/pricing.html +++ b/pricing.html @@ -11,4 +11,4 @@ --nextra-primary-hue: 204deg; --nextra-primary-saturation: 100%; } -

      新注册用户将自动获得7 天专业版免费试用评估。到期后转为免费版。

      免费版

      适用于小型应用,轻度更新需求

      0 / 年
      开始使用

      标准版

      适用于一般应用,中度更新需求

      800/ 年
      • 可创建5个应用 ,每个限*:
      • 50个原生包,每个最大150M
      • 50个热更包,每个最大15M
      • 提供专人技术支持
      立即升级

      高级版

      适用于一般应用,中度更新需求

      2400/ 年
      • 可创建10个应用,每个限*:
      • 60个原生包,每个最大500M
      • 60个热更包,每个最大50M
      • 提供专人技术支持
      立即升级

      专业版

      适用于商业应用,高速迭代需求

      7200/ 年
      • 可创建20个应用,每个限*:
      • 100个原生包,每个最大2000M
      • 100个热更包,每个最大200M
      • 提供专人技术支持
      立即升级

      如您需要更高配额,我们也提供定制版本或是私有服务器部署,您可将具体需求发送至 hi@charmlot.com 我们将第一时间回复。

      *注:iOS 和 Android 版本记做不同的应用。
      原生包指完整的apk/ipa安装包。热更包指pushy bundle命令生成的ppk文件(不是用户实际下载的增量更新文件)。
      您可删除已不再使用的应用、原生包、热更包来有效利用配额。

      对于付费业务还有其他疑问?请参考常见问题

      \ No newline at end of file +

      新注册用户将自动获得7 天专业版免费试用评估。到期后转为免费版。

      免费版

      适用于小型应用,轻度更新需求

      0 / 年
      开始使用

      标准版

      适用于一般应用,中度更新需求

      800/ 年
      • 可创建5个应用 ,每个限*:
      • 50个原生包,每个最大150M
      • 50个热更包,每个最大15M
      • 提供专人技术支持
      立即升级

      高级版

      适用于一般应用,中度更新需求

      2400/ 年
      • 可创建10个应用,每个限*:
      • 60个原生包,每个最大500M
      • 60个热更包,每个最大50M
      • 提供专人技术支持
      立即升级

      专业版

      适用于商业应用,高速迭代需求

      7200/ 年
      • 可创建20个应用,每个限*:
      • 100个原生包,每个最大2000M
      • 100个热更包,每个最大200M
      • 提供专人技术支持
      立即升级

      如您需要更高配额,我们也提供定制版本或是私有服务器部署,您可将具体需求发送至 hi@charmlot.com 我们将第一时间回复。

      *注:iOS 和 Android 版本记做不同的应用。
      原生包指完整的apk/ipa安装包。热更包指pushy bundle命令生成的ppk文件(不是用户实际下载的增量更新文件)。
      您可删除已不再使用的应用、原生包、热更包来有效利用配额。

      对于付费业务还有其他疑问?请参考常见问题

      \ No newline at end of file