[Phonegap+Sencha Touch] 移動開發77 Cordova Hot Code Push插件實現自己主動更新App的Web內容...

原文地址:http://blog.csdn.net/lovelyelfpop/article/details/50848524



插件地址:https://github.com/nordnet/cordova-hot-code-push


以下是我對GitHub項目readme的翻譯

——————————————————————————————————————————————


Cordova Hot Code Push Plugin

此插件提供了能夠使cordova app自己主動更新web內容的功能。

?基本上, 你App中全部位于?www?文件夾內的文件都能夠被自己主動更新.

當你又一次公布新的app時-又一次打包了web內容: html 文件, JavaScript 代碼, 圖片等等. 一般有兩種方式進行升級:

  1. 在appstore中上架新的app. 可是耗時比較長.

  2. 犧牲全部原生功能。每次打開都從遠端站點載入. 可是假設沒有網絡,app就沒法使用.

此插件就為了解決問題而生. 當用戶初次打開app - 它會將全部web內容復制一份到外部存儲. 此后從外部存儲載入web內容,而并不載入打包在app內部的web內容. app每次啟動都會連接server檢查更新并下載新的web內容. 假設下載了更新 - 此次更新內容將會在下次app啟動時生效.

這樣, 你的app就得到了實時更新, 而且也能在離線的時候使用. 還有,插件同意你對web內容設置最小支持的app外殼版本號, 以保證新的web內容能夠在舊的app外殼上執行.

App Store能夠上架這樣的app嗎??能夠... 僅僅要你更新后的web內容符合app一開始的功能. 假設本來是個計算器, 更新后變成了一個音樂播放器 - 這是會被禁止的.

支持平臺

  • Android 4.0.0 或以上.

  • iOS 7.0 或以上.

文檔

  • 安裝

  • 從低版本號遷移

  • Cordova 項目高速向導

  • Ionic 項目?高速向導

  • 更新機制的流程圖

  • web內容是怎樣存儲和更新的

  • Cordova Hot Code Push 命令行客戶端

  • 本地開發擴展

  • Cordova 配置項

  • 配置文件

    • Application config?app配置

    • Content manifest?內容清單

    • Build options?build設置

  • JavaScript?模塊

    • 監聽更新的事件

    • 請求更新

    • 安裝更新

    • 執行時改變插件設置

    • 請求從store更新app(外殼)

  • 錯誤碼

安裝

須要cordova 5.0+

cordova plugin add cordova-hot-code-push-plugin

也可直接從 倉庫url 安裝(不穩定)

cordova plugin add https://github.com/nordnet/cordova-hot-code-push.git

插件安裝完后,會推薦你安裝Cordova Hot Code Push 命令行client. 此客戶的能夠幫助你:

  • 方便生成必須的app配置文件;

  • 啟動本地server,監聽開發模式下的web內容變更,并直接部署新版本號.

當然,你也能夠不用這個命令行client, 僅僅是用了它會更加方便.

從低版本號遷移

從 v1.0.x 到 v1.1.x

在版本號 1.0.x 的時候,本地開發模式集成到了此插件里面. 從 v1.1.x 開始這部分功能作為了此插件的一個擴展,移到了這里. 由于 v1.0 版本號為了支持ios的Swift做了一些優化 - 升級到 v1.1.x 你須要禁用它.

又一次安裝 iOS platform的辦法:

cordova platform remove ios
cordova platform add ios

當 platform 被加入之后 - 全部插件會自己主動安裝.

進階 - 手動移除 Swift 支持. 你須要用Xcode打開 iOS 項目, 然后:

  1. 在?Build Settings,設置?Embedded Content Contains Swift Code?為?NO.

  2. 打開?<YOUR_PROJECT_NAME>-Prefix.pch?, 移除?#import <YOUR_PROJECT_NAME>-Swift.h. 比方:

    #ifdef __OBJC__#import "TestProject-Swift.h"
    #endif
  3. 又一次build, 檢查是否正常.

Cordova 項目高速向導

此向導展示了在開發中怎樣高速使用這個插件. 我們須要加入?開發擴展 。須要?Xcode 7, 雖然hot code push plugin插件自身能夠支持低版本號xcode.

  1. 創建新的Cordova項目。并加入android和iOS platform:

    cordova create TestProject com.example.testproject TestProjectcd ./TestProject
    cordova platform add android
    cordova platform add ios

    或者能夠用一個已有的項目.

  2. 加入插件:

    cordova plugin add cordova-hot-code-push-plugin
  3. 加入開發擴展:

    cordova plugin add cordova-hot-code-push-local-dev-addon
  4. 安裝 Cordova Hot Code Push 命令行client:

    npm install -g cordova-hot-code-push-cli
  5. 啟動本地server:

    cordova-hcp server

    你會看到以下的命令行輸出:

    Running server
    Checking:  /Cordova/TestProject/www
    local_url http://localhost:31284
    Warning: .chcpignore does not exist.
    Build 2015.09.02-10.17.48 created in /Cordova/TestProject/www
    cordova-hcp local server available at: http://localhost:31284
    cordova-hcp public server available at: https://5027caf9.ngrok.com
  6. 打開新的控制臺, 進入到項目根文件夾,執行app:

    cordova run

    稍等,app會安裝到手機或者模擬器.

  7. 如今打開?TestProject/www/index.html?, 做一些修改然后保存. 幾秒種后你能夠在手機或模擬器上看到更新后的頁面.

到此,你能夠本地開發。新的web內容會自己主動在設備上更新,而無需又一次啟動app查看效果.

Ionic 項目高速向導

此向導展示了在開發中怎樣高速使用這個插件. 我們須要加入?開發擴展須要?Xcode 7, 雖然hot code push plugin插件自身能夠支持低版本號xcode.

  1. 創建新的Ionic項目,并加入android和iOS platform::

    ionic start TestProject blankcd ./TestProject
    ionic platform add android
    ionic platform add ios

    Or use the existing one.

  2. 加入插件:

    ionic plugin add cordova-hot-code-push-plugin
  3. 加入開發擴展:

    ionic plugin add cordova-hot-code-push-local-dev-addon
  4. 安裝 Cordova Hot Code Push 命令行client:

    npm install -g cordova-hot-code-push-cli
  5. 啟動本地server:

    cordova-hcp server

    你會看到以下的命令行輸出:

    Running server
    Checking:  /Cordova/TestProject/www
    local_url http://localhost:31284
    Warning: .chcpignore does not exist.
    Build 2015.09.02-10.17.48 created in /Cordova/TestProject/www
    cordova-hcp local server available at: http://localhost:31284
    cordova-hcp public server available at: https://5027caf9.ngrok.com
  6. 打開新的控制臺, 進入到項目根文件夾。執行app:

    ionic run

    稍等。app會安裝到手機或者模擬器.

  7. 如今打開?TestProject/www/index.html?, 做一些修改然后保存. 幾秒種后你能夠在手機或模擬器上看到更新后的頁面.

到此,你能夠本地開發,新的web內容會自己主動在設備上更新。而無需又一次啟動app查看效果.

更新機制的流程圖

先防止全部的配置相關的內容弄得你稀里糊涂 - 先來看看此插件的實現更新功能的流程圖. 應該沒有技術細節.


  1. 用戶打開你的app.

  2. 插件初始化,在后臺進程啟動 升級載入器(update loader).

  3. Update loader ?從?config.xml?取?config-file?配置(一個url),并從此url載入一段 JSON 配置. ?然后它把這段JSON配置中的?release?版本 和當前app 已經安裝的進行比較. 假設不同 - 進入下一步.

  4. Update loader 使用app配置(application config)中的?content_url?。去載入清單文件(manifest). 它會找出自上次升級以來,哪些文件須要更新.

  5. Update loader 從?content_url下載更新文件.

  6. 假設一切順利 - 發出一個"升級文件已經準備好,能夠安裝了"的通知.

  7. 升級文件已安裝, app又一次進入更新過的頁面.

當然, 還有其它的細節, 只是你已經有了大致的思路.

web內容是怎樣存儲和更新的

每個Cordova 項目都有一個?www?文件夾, 這里存放全部的web內容. 當cordova build?運行后 -?www?里的內容會復制到相應platform的?www?文件夾下:

  • 安卓:?platforms/android/assets/www.

  • iOS:?platforms/ios/www.

于是這些文件被打包進了app. 我們不能更新安裝包里的這些文件, 由于它們是僅僅讀的. 正由于如此,所以我們要在app第一次啟動的時候,將內置的web內容(www文件夾)拷貝到外部存儲. 我們不想在拷貝過程中堵塞ui - 我們還是會先載入app內置的index.html. 可是下一次啟動或更新 - 我們就從外部存儲載入index.html.

可是假設你的app外殼需要添加新的cordova插件或者原生功能 - 你必需要又一次上架外殼app到store商店. 還有 - 添加外殼 app 的build版本 (App Store 或 Google Play強制的).下次啟動,插件檢查外殼app版本是否變化, 假設變了 - 會又一次拷貝內置web內容(www文件夾)到外部存儲.

開發app的時候 - 你可能會困惑: 改了一些文件, 又一次啟動了app - 但卻看到的是舊的頁面. 如今你知道原因了: 插件用的是舊版本號的web內容(外部存儲中). 若要清除緩存,你須要:

  • 卸載app, 運行?cordova run.

  • 添加外殼app版本,強制插件又一次安裝?www?文件夾. 更改外殼app版本請設置?config.xml文件的?android-versionCode?和?ios-CFBundleVersion?.

  • 安裝 本地開發擴展?,讓它幫你處理版本問題. 每次build他會自己主動幫你app的build版本加1,不須要你手動更改

上面就是簡要介紹, 以便你理解大致的思路. 如今我們繼續深入.

之后你會閱讀到?配置文件?這一節- 這有app配置 (application config), 名字是chcp.json. 里面有個?release設置,?這個指明了web內容的版本號. 這個配置必須并且每次公布的release版本號必須不一樣. 它由 命令行client 自己主動生成。格式是:?yyyy.MM.dd-HH.mm.ss?(比方?2015.09.01-13.30.35).

每次公布,插件在外部存儲自己主動生成一個以這個 release版本號 為名字的文件夾, 然后把web內容所有放到這里面. release版本號號成為了 url的一部分. 這個手段能夠解決一些問題:

  • 網頁內容緩存問題. 比方, iOS 上。css 文件會被 UIWebView緩存起來, 即使我們又一次加載了index.html - 新的樣式還是不會被應用. 你須要用任務管理器殺死app, 或者改變css的路徑.

  • 基本不會發生更新后損壞已有web內容的現象, 由于我們每次更新都在不同的文件夾下.

  • 即使更新導致了web內容損壞 - 我們能夠回滾到上一個版本號的release.

比方, 我們當前執行的release版本號是?2015.12.01-12.01.33. 這意味著:

  • 全部web內容存儲在?/sdcard/some_path/2015.12.01-12.01.33/www/. 包括了Cordova的資源.

  • Index 頁面, 用戶看到的是?/sdcard/some_path/2015.12.01-12.01.33/www/index.html.

某個時候我們公布了一個新的release:?2016.01.03-10.45.01. 第一步,插件須要下載新的web文件, 發生情況例如以下:

  1. 在外部存儲創建了一個以新的 release 版本為名字的文件夾:?/sdcard/some_path/2016.01.03-10.45.01/.

  2. 文件夾里面 - 又創建了一個?update?文件夾 :?/sdcard/some_path/2016.01.03-10.45.01/update/.

  3. 全部依據?chcp.manifest?更新的文件 都被下載到了這個?update?文件夾內.

  4. 新的?chcp.manifest?和?chcp.json?也被放到了?update?文件夾內.

  5. 新的web內容已準備安裝.

安裝更新的時候:

  1. 插件從當前正在使用的release版本號 文件夾內拷貝?www?下全部內容到 新的 release 版本號文件夾下. 用我們的樣例就是:從?/sdcard/some_path/2015.12.01-12.01.33/www/?拷貝全部文件到?/sdcard/some_path/2016.01.03-10.45.01/www/.

  2. update?文件夾下拷貝新的web內容和配置文件,到?www?文件夾下:?/sdcard/some_path/2016.01.03-10.45.01/update/?->?/sdcard/some_path/2016.01.03-10.45.01/www/.

  3. 移除?/sdcard/some_path/2016.01.03-10.45.01/update/?文件夾。由于我們不再使用了.

  4. 載入新的release版本號index.html:?/sdcard/some_path/2016.01.03-10.45.01/www/index.html.

至此。插件會從新的release載入頁面, 而舊的release則會作為一個備份留下來,以防萬一.

Cordova Hot Code Push 命令行client

Cordova Hot Code Push 命令行client?是一個命令行工具,以便你web內容的開發.

它能夠:

  • 生成?chcp.json?和?chcp.manifest?文件, 這樣你就不用手動去創建;

  • 執行本地服務,開發時能夠檢測更新,并公布新的release版本號,使得能夠再設備上實時更新web內容;

  • 部署你的web內容到外部server上.

當然, 你能夠不使用這個命令行工具. 僅僅是用了它會更方便一些.

本地開發擴展

當你本地開發app時 - 一般做法類似:

  1. web項目做一些更改.

  2. 運行?cordova run?啟動app.

  3. 稍等一會查看執行結果.

即使非常小的變更也須要打包重裝app. 耗時比較久,比較麻煩.

為了提升速度 - 你能夠使用本地開發擴展?Hot Code Push Local Development Add-on. 安裝非常簡答:

  1. 加入此cordova插件.

  2. 啟動本地服務?cordova-hcp server.

  3. 在你的項目的config.xml?文件里?<chcp />?塊下加入?<local-development enabled="true" />.

  4. 啟動app.

這樣, 全部web內容的變更都會被插件檢測到, 并直接更新顯示到app上,而不須要重新啟動app.

僅僅有在加入了新的cordova插件時你才會重新啟動app.

重要:?你應該僅僅在開發狀態下使用此擴展. 公布外殼app的時候,應該移除此擴展:?cordova plugin remove cordova-hot-code-push-local-dev-addon.

Cordova 配置項

你應該知道, Cordova 使用?config.xml?文件配置不同項目: app名字, 描寫敘述, 起始頁面,等等. 使用config.xml文件。你也能夠為此插件配置.

這些配置位于?<chcp>?塊. 比方:

<chcp><config-file url="https://5027caf9.ngrok.com/chcp.json"/>
</chcp>
config-file

定義了一個 URL。指定了須要從哪里載入app配置(application config,就是chcp.json). URL 在?url?屬性中聲明.?此項必須.

以防萬一,開發的時候, 假設?config-file?未定義 - 會自己主動設為本地服務上?chcp.json?的路徑.

auto-download

自己主動下載web內容更新. 默認是自己主動, 假設你想手動下載web內容更新,你能夠使用 JavaScript 模塊(以下有).

禁用自己主動下載能夠設置?config.xml:

<chcp><auto-download enabled="false" />
</chcp>

默認是?true.

auto-install

自己主動安裝. web內容更新. 默認是自己主動, 假設你想手動安裝web內容更新,你能夠使用 JavaScript 模塊(以下有).

禁用自己主動安裝能夠設置?config.xml:

<chcp><auto-install enabled="false" />
</chcp>

默認是?true.

配置文件

此插件用到2個配置文件:

  • app配置?Application config?- 包括最新的release信息: release 版本, 最低須要的外殼app版本,等等. 文件名稱?chcp.json

  • Web內容清單?Content manifest?- 包括全部web內容文件的名字和MD5值. 文件名稱?chcp.manifest

這兩個文件必須. 他們描寫敘述了是否有新的release版本號,以及文件更新時的比較.

另一個build 可選參數 (build options)?文件, 能夠再運行cordova build?命令時指定插件的配置.

Application config?app配置

包括最新版本號的release信息.

簡單的樣例:

{  "content_url": "https://5027caf9.ngrok.com",  "release": "2015.09.01-13.30.35"}

這個文件應該放在?www?文件夾下,文件名稱是?chcp.json?.?這個文件也被打包到了外殼app內.

你能夠手動創建它, 或者用?cordova-hcp?命令(Cordova Hot Code Push 命令行)自己主動生成. 僅僅要在cordova項目根文件夾下執行?cordova-hcp init?, 以后要公布新的release僅僅要執行?cordova-hcp build. 很多其它內容請閱讀?命令行client的文檔.

content_url

服務端URL, 也就是你全部web內容文件的位置. 插件會把它作為下載新的清單文件、新的web內容文件的 base url.?此項必須.

release

不論什么字符串. 每次release應該唯一. 插件基于這個才知道有沒有新版本號release.?此項必須.

重要:?插件僅僅比較release字符串是否相等, 假設不等,就覺得服務端有新版本號.(不會比較大小)

min_native_interface

所需最小的外殼app版本號. 這是app的build版本號號。是個整型數字, 不是應用商店中看到的形如"1.0.0"字符串.

在?config.xml中。這樣指定build版本:

<widget id="io.cordova.hellocordova"version="1.0.1"android-versionCode="7"ios-CFBundleVersion="3">
  • version?- app字符串版本號號, 也就是用戶在商店中看到的版本號.

  • android-versionCode?- 安卓的build版本. 這個應該用于?min_native_interface.

  • ios-CFBundleVersion?- iOS的build版本.這個應該用于?min_native_interface.

Preference creates dependency between the web and the native versions of the application.

重要:?由于cordova的一個奇葩現象, 生成的?.apk?的build版本會被加 10, 導致了變成了形如 70, 72, or 74, 依據不同平臺 (arm/x86/etc),后面的0、2、4不一樣. 為了繞過這個, 我們建議也給 iOS build版本手動加10, 這樣?min_native_interface?(比方?70) 就能夠對安卓和iOS都有效, 大致是這樣:

<widget id="io.cordova.hellocordova"version="1.0.1"android-versionCode="7"ios-CFBundleVersion="70">

舉個樣例, 如果你的外殼app加了個新的插件 - 你應該會更新外殼app. 為了防止用戶下載了不適合他現有外殼app的web內容 - 你應該設置?min_native_interface?這個值.

比方, 我們app里的chcp.json是這種:

{  "content_url": "https://5027caf9.ngrok.com",  "release": "2015.09.01-13.30.35",  "min_native_interface": 10}

外殼app的build版本號是?13.

某個時候,web內容有了新的release公布:

{  "content_url": "https://5027caf9.ngrok.com",  "release": "2015.09.05-12.20.15",  "min_native_interface": 15}

插件載入到這段json的時候, 發現?min_native_interface?比當前外殼app的build號要大 - 它就不會下載web內容. 而是觸發一個?chcp_updateLoadFailed?錯誤通知, 告訴用戶須要升級外殼app了. 很多其它內容請看 從應用商店請求app升級 ?小節.

備注:?眼下你還不能為不同平臺指定不同的?min_native_interface?. 假設須要以后能夠支持.

update

指定了什么時候安裝web內容更新. 支持的值有:

  • start?- app啟動時安裝更新. 默認值.

  • resume?- app從后臺切換過來的時候安裝更新.

  • now?- web內容完成下載即安裝更新.

你能夠用JavaScript禁止自己主動安裝. 請看?JavaScript module?小節.

android_identifier

apk包名. 假設指定了 - 引導用戶到 Google Play Store 的app頁面.

ios_identifier

ios應用標識號, 比方:?id345038631. 假設指定了 - 引導用戶到 App Store 的app頁面.

Content manifest內容清單

內容清單描寫敘述了web項目全部文件的狀態.

[{    "file": "index.html",    "hash": "5540bd44cbcb967efef932bc8381f886"},{    "file": "css/index.css",    "hash": "e46d9a1c456a9c913ca10f3c16d50000"},{    "file": "img/logo.png",    "hash": "7e34c95ac701f8cd9f793586b9df2156"},{    "file": "js/index.js",    "hash": "0ba83df8459288fd1fa1576465163ff5"}
]

依據它,插件才知道什么文件被移除了, 什么文件更新或新增了. 于是:

  • 更新階段。從服務端下載全部web內容文件;

  • 安裝階段,刪除服務端不存在(已移除)的文件.

這個文件應該放在?www?文件夾下,文件名稱是?chcp.manifest?.這個文件也被打包到了外殼app內.

相同的, 清單文件要放到?content_url?(app配置 Application config中指定的)指定的文件夾下. 比方, 假設你的?content_url?是?https://somedomain.com/www, 這個清單文件的url就必須是?https://somedomain.com/www/chcp.manifest.

生成?chcp.manifest?文件能夠運行命令行client的?build?命令 (在cordova項目根文件夾下運行):

cordova-hcp build
file

相對于?www?的路徑(就是你存放web內容的地方).

比方, 你的web內容位于:??/Workspace/Cordova/TestProject/www.??你的?file?值應該是相對于這個路徑.

hash

文件的 MD5 值. 用于檢測自上次release以來。這個文件是否變更過. 還實用于檢測app端下載的文件是否出錯.

建議:?每次變更web內容后都應該更新?chcp.manifest?文件. 否則插件不會檢測到不論什么更新.

Build options?build設置

就像在?Cordova 配置項?一節中說的 - 你能夠在config.xml?文件中改變插件配置.

可是假設你想在使用build命令行的時候改變插件配置呢? 為了達到這個目的,你須要使用chcpbuild.options?文件.

文件必須位于 Cordova 項目根文件夾. 在這個文件中面。你指定(JSON格式) 全部你想改變?config.xml?文件的配置. 源文件?config.xml?(Cordova項目根文件夾) 不會發生變動, 我們改變的是 特定平臺下的?config.xml? (在cordova build過程的?after_prepare?階段).

比方, 你的Cordova項目是?/Cordova/TestProject?文件夾.config.xml?文件 (/Cordova/TestProject/config.xml) 有以下的配置:

<chcp><config-file url="https://company_server.com/mobile/www/chcp.json" />
</chcp>

這時我們在?/Cordova/Testproject/?下創建?chcpbuild.options?文件,文件內容例如以下:

{"dev": {"config-file": "https://dev.company_server.com/mobile/www/chcp.json"},"production": {"config-file": "https://company_server.com/mobile/www/chcp.json"},"QA": {"config-file": "https://test.company_server.com/mobile/www/chcp.json"}
}

build app的時候, 轉為開發要用的server, 可運行:

cordova build -- chcp-dev

結果就是, 特定拍下的?config.xml?文件(比方,?/Cordova/TestProject/platforms/android/res/xml/config.xml) 變成了這樣:

<chcp><config-file url="https://dev.company_server.com/mobile/www/chcp.json"/>
</chcp>

你可能注意到了 - 我們用的命令有個?chcp-. 這個必須, 這樣插件才知道, 這個參數是為它設置的. 并且, 不會和其他插件的命令參數沖突.

假設你的app能夠測試了 - 你能夠用以下的命令build, 就指定了測試server:

cordova build -- chcp-QA

特定平臺下的?config.xml?就會變成:

<chcp><config-file url="https://test.company_server.com/mobile/www/chcp.json"/>
</chcp>

當我們須要上架app的時候 (Google Play, App Store) - 我們正常build:

cordova build --release

這樣?config.xml?是不會改變的.

假設沒有使用?chcpbuild.options? - 插件會使用?config.xml?面默認的值.

JavaScript 模塊

默認情況下, 全部的 檢查更新->下載->安裝 過程都是插件在原生端自己主動進行的. 不須要其他js端代碼. 然而, 這些過程也能夠用js控制.

你能夠:

  • 監聽更新相關的事件;

  • 從服務端檢查和下載新的web內容;

  • 安裝已下載的web內容;

  • 更改插件配置;

  • 讓用戶到應用商店下載新的外殼app.

監聽更新事件

比方, web內容已經下載并能夠安裝了。會有事件通知, 或者出錯了導致安裝新的web內容失敗了.

監聽事件像這樣:

  document.addEventListener(eventName, eventCallback, false);function eventCallback(eventData) {// do something}

錯誤事件有具體錯誤信息. 像這樣:

function eventCallback(eventData) {var error = eventData.details.error;if (error) {console.log('Error with code: ' + error.code);console.log('Description: ' + error.description);}
}

可用的事件例如以下:

  • chcp_updateIsReadyToInstall?- web內容已經下載并能夠安裝時觸發.

  • chcp_updateLoadFailed?- 插件無法下載web更新時觸發. 具體錯誤信息在事件參數里.

  • chcp_nothingToUpdate?- 無可用更新下載時觸發.

  • chcp_updateInstalled?- web內容成功安裝時觸發.

  • chcp_updateInstallFailed?- web內容安裝失敗時觸發.?具體錯誤信息在事件參數里.

  • chcp_nothingToInstall?-無可用更新安裝時觸發.

  • chcp_assetsInstalledOnExternalStorage?- 插件成功把app內置的web內容復制到外置存儲中時觸發. 你可能須要開發調試時用到這個事件。或許不會.

  • chcp_assetsInstallationError?-插件無法拷貝app內置的web內容到外置存儲中時觸發. 假設此事件發生了 - 插件不再工作. 或許是設備沒有足夠的存儲空間導致. ?具體錯誤信息在事件參數里.

該舉一些簡單的樣例了. 如果我們有個?index.js?文件, 它被?index.html引用.

var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: function() {console.log('Device is ready for work');}
};app.initialize();

這個和cordova默認創建的?index.js?文件非常像. 監聽?chcp_updateIsReadyToInstall?事件例如以下:

bindEvents: function() {// ...some other events subscription code...document.addEventListener('chcp_updateIsReadyToInstall', this.onUpdateReady, false);
},

編寫事件處理函數:

// chcp_updateIsReadyToInstall Event Handler
onUpdateReady: function() {console.log('Update is ready for installation');
}

?index.js?結果例如以下:

var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);document.addEventListener('chcp_updateIsReadyToInstall', this.onUpdateReady, false);},// deviceready Event HandleronDeviceReady: function() {console.log('Device is ready for work');},// chcp_updateIsReadyToInstall Event HandleronUpdateReady: function() {console.log('Update is ready for installation');}
};app.initialize();

這樣我們就知道了web內容什么時候完成下載并能夠安裝了. 通過 JavaScript 模塊我們能夠讓插件即時安裝web更新, 否則將在下次啟動app時安裝.

檢查更新

使用js代碼。讓插件檢查更新:

chcp.fetchUpdate(updateCallback);function updateCallback(error, data) {// do some work
}

回調有2個參數:

  • error?- 假設檢查失敗,有error參數;?null?表示一切正常;

  • data?- 額外的 數據, 原生端提供. 臨時能夠忽略.

我們如果?index.html?有一些button, 按下它能夠檢查更新. 我們須要這樣寫代碼:

  1. 監聽button的?click?事件.

  2. 當點擊button時調用chcp.fetchUpdate()?.

  3. 處理更新事件的結果.

我們來改?index.js?代碼:

var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: function() {// Add click event listener for our update button.// We do this here, because at this point Cordova modules are initialized.// Before that chcp is undefined.document.getElementById('myFetchBtn').addEventListener('click', app.checkForUpdate);},checkForUpdate: function() {chcp.fetchUpdate(this.fetchUpdateCallback);},fetchUpdateCallback: function(error, data) {if (error) {console.log('Failed to load the update with error code: ' + error.code);console.log(error.description);} else {console.log('Update is loaded');}}
};app.initialize();

注意:?即使你在fetchUpdate?回調里處理了,相關的更新事件還是會觸發并廣播的.

安裝web更新

調用:

chcp.installUpdate(installationCallback);function installationCallback(error) {// do some work
}

假設安裝失敗 -?error?參數會有錯誤具體信息. 否則- 為?null.

如今讓我們來繼續上面的代碼,處理web內容下載完后的安裝.

var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: function() {// Add click event listener for our update button.// We do this here, because at this point Cordova modules are initialized.// Before that chcp is undefined.document.getElementById('myFetchBtn').addEventListener('click', app.checkForUpdate);},checkForUpdate: function() {chcp.fetchUpdate(this.fetchUpdateCallback);},fetchUpdateCallback: function(error, data) {if (error) {console.log('Failed to load the update with error code: ' + error.code);console.log(error.description);return;}console.log('Update is loaded, running the installation');chcp.installUpdate(this.installationCallback);},installationCallback: function(error) {if (error) {console.log('Failed to install the update with error code: ' + error.code);console.log(error.description);} else {console.log('Update installed!');}}
};app.initialize();

注意:?即使你在?installUpdate?回調里處理了,相關的更新事件還是會觸發并廣播的

執行時改變插件設置

正常情況下,全部的插件配置都在?config.xml. 可是你能夠用js動態改變.

通過以下的代碼實現:

chcp.configure(options, callback);function callback(error) {// do some work
}

支持的有:

  • config-file?- application config(chcp.json) 的url. 假設設置了 - 這個url將會被用于檢查更新,而不是config.xml中的值.

  • auto-download?- 設為?false?你能夠禁止插件自己主動檢測web內容更新并下載.

  • auto-install?- 設為?false?你能夠禁止插件自己主動安裝web更新.

這些須要在?deviceready?事件中設置. 你應該在每一個頁面載入的時候處理,?

假如你一開就打算手動更新和下載安裝 - 你應該在config.xml中設置

<chcp><auto-download enabled="false" /><auto-install enabled="false" />
</chcp>

而不是js端動態設置.

比方, 我們在config.xml禁用了?auto-download?and?auto-install??. 然后某個時間點?config-file?改變了, 可是我們不想從原有的url檢測和下載web更新. 此時, 我們應該這樣:

  1. 公布新版本號的web內容, 它們能夠用于最初的?config-file?url.

  2. 在新的版本號?index.js?文件里,內容像這樣:

    var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);},// deviceready Event HandleronDeviceReady: function() {// change plugin optionsapp.configurePlugin();},configurePlugin: function() {var options = {'config-file': 'https://mynewdomain.com/some/path/mobile/chcp.json'};chcp.configure(options, configureCallback);},configureCallback: function(error) {if (error) {console.log('Error during the configuration process');console.log(error.description);} else {console.log('Plugin configured successfully');app.checkForUpdate();}},checkForUpdate: function() {chcp.fetchUpdate(this.fetchUpdateCallback);},fetchUpdateCallback: function(error, data) {if (error) {console.log('Failed to load the update with error code: ' + error.code);console.log(error.description);return;}console.log('Update is loaded, running the installation');chcp.installUpdate(this.installationCallback);},installationCallback: function(error) {if (error) {console.log('Failed to install the update with error code: ' + error.code);console.log(error.description);} else {console.log('Update installed!');}}
    };app.initialize();


引導用戶去應用商店更新外殼app

從?Application config?app配置?小節我們知道。能夠給web更新設置最小支持的外殼app版本號 (min_native_interface?). 假設插件檢查發現用戶安裝的外殼app版本號比服務端新的web內容要求的版本號要低 - 就會觸發錯誤事件。錯誤碼chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW. 通過這個錯誤碼我們能夠引導用戶去應用商店更新外殼app (Google Play /App Store).

這里你想怎么做就怎么做. 經常用法是顯示一個對話框,問用戶是否須要轉到應用商店. 插件也提供了這個.

你須要做的是:

  1. 在 application config(chcp.json) 中設置t?android_identifier?和 ?ios_identifier.

  2. js端監聽對應事件,并在出現錯誤的時候調用?chcp.requestApplicationUpdate?方法.

舉個樣例. 簡單起見我們監聽?chcp_updateLoadFailed?事件.

var app = {// Application Constructorinitialize: function() {this.bindEvents();},// Bind any events that are required.// Usually you should subscribe on 'deviceready' event to know, when you can start calling cordova modulesbindEvents: function() {document.addEventListener('deviceready', this.onDeviceReady, false);document.addEventListener('chcp_updateLoadFailed', this.onUpdateLoadError, false);},// deviceready Event HandleronDeviceReady: function() {},onUpdateLoadError: function(eventData) {var error = eventData.detail.error;if (error && error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW) {console.log('Native side update required');var dialogMessage = 'New version of the application is available on the store. Please, update.';chcp.requestApplicationUpdate(dialogMessage, this.userWentToStoreCallback, this.userDeclinedRedirectCallback);}},userWentToStoreCallback: function() {// user went to the store from the dialog},userDeclinedRedirectCallback: function() {// User didn't want to leave the app.// Maybe he will update later.}
};app.initialize();

錯誤碼

下載安裝web更新的過程中可能會發生一些錯誤. 你能夠從回調或者事件中匹配錯誤碼(?chcp.error?對象中有各種錯誤碼).

v1.2.0版本號之前 你須要用特定的錯誤碼數字值. 此時開始, 請使用靜態常量名,這樣能夠使代碼可讀。也能夠降低對錯誤碼詳細數字的依賴. 比方, 不應該用?if (error.code == -2)?而用?if (error.code == chcp.error.APPLICATION_BUILD_VERSION_TOO_LOW).

錯誤列表:

  • NOTHING_TO_INSTALL?- 請求插件安裝更新。卻沒有更新須要安裝. 值為?1.

  • NOTHING_TO_UPDATE?- 沒有可用web更新須要下載.值為?2.

  • FAILED_TO_DOWNLOAD_APPLICATION_CONFIG?- 下載新的application config 文件(chcp.json)失敗. 要么文件不存在或者網絡問題.值為?-1.

  • APPLICATION_BUILD_VERSION_TOO_LOW?- 外殼app的build版本太低. 新的web內容須要新的外殼app. 用戶須要更新外殼app.值為?-2.

  • FAILED_TO_DOWNLOAD_CONTENT_MANIFEST?- 下載內容清單文件(chcp.manifest)失敗. 文件chcp.manifest?必須位于?content_url?相應文件夾下,?和chcp.json一起.值為?-3.

  • FAILED_TO_DOWNLOAD_UPDATE_FILES?- 下載web內容失敗. 清單?chcp.manifest?中列出文件的必須都要位于?content_url?相應文件夾下. 還有, 檢查各個文件的MD5是否正確.?值為?-4.

  • FAILED_TO_MOVE_LOADED_FILES_TO_INSTALLATION_FOLDER?- 移動已下載的文件到安裝文件夾時失敗. 可能存儲空間不足.值為?-5.

  • UPDATE_IS_INVALID?- web內容已損壞. 安裝之前。插件會檢查已下載文件的MD5和?chcp.manifest?中的比較看是否一致. 假設不一致或者文件缺失 - 會發生此錯誤. 值為?-6.

  • FAILED_TO_COPY_FILES_FROM_PREVIOUS_RELEASE?- 從上一版本號拷貝www下文件到新版本號www文件夾出錯.可能存儲空間不足.值為?-7.

  • FAILED_TO_COPY_NEW_CONTENT_FILES?- 拷貝新文件到內容文件夾下失敗.可能存儲空間不足.值為?-8.

  • LOCAL_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND?- 載入本地chcp.json失敗. 可能是用戶手動刪除了外部存儲的web內容相關文件. 假設發生。會回滾至上移release版本號的web內容.值為?-9.

  • LOCAL_VERSION_OF_MANIFEST_NOT_FOUND?-載入本地chcp.manifest失敗.可能是用戶手動刪除了外部存儲的web內容相關文件. 假設發生。會回滾至上移release版本號的web內容. 值為?-10.

  • LOADED_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND?-載入本地已下載的新版本號的chcp.json失敗.可能是用戶手動刪除了外部存儲的web內容相關文件.假設發生?- app下次啟動時會恢復. 值為?-11.

  • LOADED_VERSION_OF_MANIFEST_NOT_FOUND?-載入本地已下載的新版本號的chcp.manifest失敗.可能是用戶手動刪除了外部存儲的web內容相關文件.假設發生 -?app下次啟動時會恢復.值為?-12.

  • FAILED_TO_INSTALL_ASSETS_ON_EXTERNAL_STORAGE?- 拷貝app內置web內容到外部存儲時失敗.可能存儲空間不足. app初次啟動時會運行此操作. 假設失敗。插件就不再實用了. 值為?-13.

  • CANT_INSTALL_WHILE_DOWNLOAD_IN_PROGRESS?- 調用?chcp.installUpdate?而 插件正在下載更新時觸發. 你必須等待完成下載. 值為?-14.

  • CANT_DOWNLOAD_UPDATE_WHILE_INSTALLATION_IN_PROGRESS?- 調用?chcp.fetchUpdate?而安裝過程在再運行. 你必須等待安裝完成. 值為?-15.

  • INSTALLATION_ALREADY_IN_PROGRESS?- 調用?chcp.installUpdate,而安裝過程在再運行.值為?-16.

  • DOWNLOAD_ALREADY_IN_PROGRESS?- 調用?chcp.fetchUpdate,而 插件正在下載更新時觸發. 值為?-17.

  • ASSETS_FOLDER_IN_NOT_YET_INSTALLED?- 調用?chcp?方法, 而插件正在拷貝app內置web內容到外部存儲時觸發. 僅僅可能在app初次啟動時發生. 最后這個錯誤會被移除.值為?-18.




關于熱更新的流程解析

好多同學都測試不成功。大家不要想太復雜了。我再簡要概括一下:

  1. chcp.json文件里的content_url為server項目的地址加port號

  2. config.xml為server項目地址加port號再加上/chcp.json

  3. 每次改動完文件后。必須將【改動的文件】和【chcp.manifest文件】一并拷貝到server項目中進行覆蓋。

  4. 將server中的chcp.json文件里的【"release": "2016.08.04-18.04.06"】時間改為當前時間。

3 和 4是最重要的。不然熱更新就不起作用。

最后你們不要在糾結cordova-hcp server,這個東西就是在開發的時候啟動用來監聽文件的改動。假設有文件改動。就相應在chcp.manifest中改動該文件的hash值。

還沒完。為了更清楚的了解熱更新是怎么回事,這里我畫了一張圖。

[熱更新的流程解析]


  1. app啟動

  2. 從server請求chcp.json文件(會覆蓋本地chcp.json文件)。

  3. server返回chcp.json文件與app里的chcp.json文件做對照,推斷兩個文件里的release時間。

  4. 假設serverchcp.json文件的release時間大于app里chcp.json的release時間(說明新的資源)

  5. 假設有新的資源。再次發送一個請求,請求server的chcp.manifest文件(會覆蓋本地chcp.json文件)。

  6. server返回chcp.manifest文件與app里的chcp.manifest文件內容做對照。

  7. 假設有不一樣的hash值。

  8. 對server請求新的資源。

  9. 請求成功的資源將覆蓋本地資源。


案例

這里通過對app進行抓包,來分析熱更新是如何進行應用內更新的。注意看1~8。我是沒有對server資源進行更新的。直到第9個請求的時候:9。10,11連續發送了3個請求。

[熱更新的抓包圖]

  • 第9個請求將server的chcp.json文件請求回來后推斷時間是大于app的chcp.json時間的

  • 然后發送了第10個請求。chcp.manifest,與本地chcp.manifest文件做對照

  • 當中我僅僅改了一個login.html,所以這里對login.html又一次載入覆蓋。



一直有人問我,用不了。不會用之類的。我在這說一下

用 cordova-hcp server 命令啟動 hcp 服務器的時候,會看到如上圖的local serverpublic server,這兩個地址是不能自定義

類似“https://f5f6894c.ngrok.io” 這個地址貌似并沒實用,或許僅僅是國內沒法用吧
所以。我建議不要用 cordova-hcp server,你須要自己部署一個服務器,托管 www 下的 web 內容
Local Development Add-on 這個擴展也能夠不要,記得自己生成新的apk/ipa之前要改config.xml的version(android-versionCode/ios-CFBundleVersion)即可了

事實上 cordova-hcp server 啟動的那個服務器。就是多了2個功能:
1、檢測到 www 變更后。自己主動生成清單文件 chcp.manifest
2、自己主動實時推送變更到app端

用了你自己的server之后,這2個功能都沒了。所以
1、每次更改 www 下的 web 內容之后,一定要手動用 cordova-hcp build(在corodva項目根文件夾下運行), 生成清單文件 chcp.manifest
2、app 僅僅能在每次啟動的時候。才干檢查有無內容更新。有更新就會在后臺下載。等到下次啟動 app 才應用更新。

(也就是要重新啟動app 2次才干看到效果)

chcp.json 這個文件的內容也要改下,把?update 改為 "start",比方

{"update": "start","content_url": "http://10.0.0.100/HCP/","release": "2016.04.28-10.14.32"
}

chcp.json?的功能,不懂的看上面翻譯


能夠在 cordova 項目根文件夾下放一個 cordova-hcp.json,這是個模板文件
這樣每次運行 cordova-hcp build, 就會利用這個模板生成新的 chcp.json,而不用手動更改 www/chcp.json了。
cordova-hcp.json內容例如以下:
{"update": "start","content_url": "http://10.0.0.100/HCP/"
}




常見問題解決的方法:

1、假設用安卓模擬器測試的,請確保手機模擬器的時區、時間和server時區、時間一致。否則。版本對不上。就檢測不到更新了








歡迎增加Sencha Touch + Phonegap交流群

1群:194182999?(滿)

2群:419834979

共同學習交流(博主QQ:479858761)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/540940.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/540940.shtml
英文地址,請注明出處:http://en.pswp.cn/news/540940.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java 如何重寫迭代器,如何用Java按需定制自己的迭代器

編寫自己的迭代器的流程是&#xff1a;首先實現Iterable接口&#xff0c;進而實現該接口中的Iterator iterator()方法&#xff0c;該方法返回接口Iterator&#xff0c;Iterator接口中封裝了next&#xff0c;hasnext&#xff0c;remove等方法。實現了Iterable接口的類能夠通過fo…

count函數里加函數_PHP count()函數與示例

count函數里加函數PHP count()函數 (PHP count() function) "count() function" is used to get the total number of elements of an array. “ count()函數”用于獲取數組元素的總數。 Syntax: 句法&#xff1a; count(array, [count_mode])Here, 這里&#xff0…

php整合支付寶,Thinkphp5.0整合支付寶在線下單

thinkphp5.0支付寶在線支付下單整個流程&#xff0c;包括創建訂單、支付成功回調更新訂單狀態、最終跳轉到商戶訂單詳情頁查看演示下載資源&#xff1a;17次 下載資源下載積分&#xff1a;998積分支付寶在線支付控制器代碼 public function alipay() {//發起支付寶支付$order_n…

python函數示例_PHP closeir()函數與示例

python函數示例PHP Closedir()函數 (PHP closedir() function) The full form of closedir is "Close Directory", the function closedir() is used to close an opened directory. Closedir的完整格式為“ Close Directory” &#xff0c; 函數closedir()用于關閉打…

java宋江,Java編程內功-數據結構與算法「單鏈表」,

package com.structures.linkedlist;public class SingleLinkedListDemo {public static void main(String[] args) {HeroNode heroNode1 new HeroNode(1, "宋江", "及時雨");HeroNode heroNode2 new HeroNode(2, "盧俊義", "玉麒麟"…

智能家居逐漸融入AI技術 向大眾市場擴張仍需時間

雖然智能家居變得越來越普遍&#xff0c;并且大眾認知度越來越高&#xff0c;但是在這一技術變得像智能手機一樣無處不在之前&#xff0c;OEM和服務提供商仍然有很長的路要走。 在2016年11月在硅谷舉行的智能家居峰會上&#xff0c;代表們聽到了來自整個價值鏈上的聲音&#xf…

python 示例_Python使用示例設置add()方法

python 示例設置add()方法 (Set add() Method) add() method is used to add an element to the set, the method accepts an element and adds the elements to this set. add()方法用于將元素添加到集合中&#xff0c;該方法接受元素并將元素添加到該集合中。 Note: If the …

php怎么引用表單元素,表單元素:最全的各種html表單元素獲取和使用方法總結...

表單是網頁與用戶的交互工具&#xff0c;由一個元素作為容器構成&#xff0c;封裝其他任何數量的表單控件&#xff0c;還有其他任何元素里可用的標簽&#xff0c;表單能夠包含、、、、、等表單控件元素。表單元素有哪些呢&#xff1f;它包含了如下的這些元素&#xff0c;輸入文…

數據中心部署氣流遏制系統需要考慮的十大要素

數據中心氣流遏制策略能夠大幅提高傳統數據中心制冷系統的可預測性和效率。事實上&#xff0c;綠色網格組織&#xff08;The Green Grid&#xff09;將氣流管理策略稱作“實施數據中心節能計劃的起點”。但是&#xff0c;大多數已有數據中心由于受各種條件的制約&#xff0c;只…

JAVA語言異常,Java語言中的異常

1、異常分類從產生源頭來看&#xff0c;Java語言中的異常可以分為兩類&#xff1a;JVM拋出的異常。比如&#xff1a;訪問null引用會引發NullPointerException&#xff1b;0作為除數&#xff0c;如9/0&#xff0c;JVM會拋出ArithmeticException&#xff1b;內存消耗完&#xff0…

使用Mybatis Generator結合Ant腳本快速自動生成Model、Mapper等文件的方法

新建generatorConfig.xml和build_mybatis.xml&#xff1a; jar下載 <dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency> <depe…

java bitset_Java BitSet or()方法與示例

java bitsetBitSet類或()方法 (BitSet Class or() method) or() method is available in java.util package. or()方法在java.util包中可用。 or() method is used to perform logical OR between this BitSet and the given BitSet(bs). This BitSet is updated when either t…

matlab 細化函數,MATLAB圖像處理工具箱函數(細化篇).doc

MATLAB圖像處理工具箱函數(細化篇)第3章 MATLAB數字圖像處理工具箱3.1 MATLAB圖像預處理3.1.1 圖像處理的基本操作1. 讀入并顯示一幅圖像clear %清除所有的工作平臺變量close all %關閉已打開的圖形窗口Iimread (pout.tif); %讀取圖像pout.tif(該圖像是圖像處理工具箱自帶的圖像…

STM32啟動解析

啟動方式對的不同下載模式 STM32可以通過BOOT引腳的配置&#xff0c;來選擇不同的啟動模式------對應不同的下載方式。 仿真器下載—— 內部FLASH的啟動方式 串口下載 —— 系統存儲器的啟動方式 內部SRAM一般不用&#xff0c;不講 啟動過程 以內部FLASH的啟動方式為例&am…

OpenBSD基金會收到錘子科技約140萬捐贈款

11月26日消息&#xff0c;給開源項目捐款一向是錘子科技發布會的傳統&#xff0c;去年發布會的門票收入捐給了國人章亦春主導的開源項目OpenResty。今年&#xff0c;錘子科技選擇將收益捐贈給OpenBSD基金會。OpenBSD基金會收到錘子科技約140萬捐贈款 OpenBSD基金會11月23日發布…

自動化部署kvm虛擬機_自動化虛擬助手

自動化部署kvm虛擬機The automated virtual assistant or commonly called personal assistants, are developed to serve its users by performing some tasks, setting reminders and much more based on the input is given and local awareness. It is integrated with a l…

php 數據庫編碼,php怎么設置數據庫編碼方式

在php中&#xff0c;可以使用mysql_query()函數來設置mysql數據庫的編碼方式&#xff1b;具體方法&#xff1a;在mysql_connect()語句之后添加“mysql_query("set names 編碼方式");”代碼即可。本教程操作環境&#xff1a;windows7系統、PHP7.1版&#xff0c;DELL G…

mysql截取字符串與reverse函數

mysql的函數大全&#xff1a; http://www.jb51.net/Special/606.htm 這個網頁上很多知識點&#xff0c;可以學習下&#xff0c;關于mysql的函數&#xff0c;也可以作為API查詢&#xff1a; 這里只說下mysql的截取函數和reverse函數&#xff1a; MySQL 字符串截取函數&#xff1…

flask sql外鍵使用_如何在SQL中使用外鍵?

flask sql外鍵使用Basically, Foreign Key represents relationship between tables. 基本上&#xff0c; 外鍵代表表之間的關系 。 Syntax: 句法&#xff1a; column-name data_type (size) CONSTRAINT constraint-name References Table-name (Column-name)Example: 例&a…

php發展歷,PHP的發展歷程

PHP的發展歷程了解一門語言&#xff0c;我們必須知道這門語言的發展史&#xff0c;現在我通過版本的變化以時間軸的形式來說明PHP的發展歷程。1.1995年初PHP1.0誕生Rasmus Lerdof發明了PHP&#xff0c;這是簡單的一套Perl腳本&#xff0c;用來跟蹤訪問者的信息。這個時候的PHP只…