DaoCloud+是一個使用 Electron 迷你的托盤控制臺程序,而且在寫這個程序的時候最重要的原因就是希望能及時獲取到我的鏡像構(gòu)建和應(yīng)用運行(接口原因,目前無法支持)狀態(tài),但如果應(yīng)用不能主動推送通知給我,那么這個應(yīng)用能提供給我的價值就是微乎其微了。


那么現(xiàn)在問題來了,在沒有官方的推送服務(wù)支持時,如果能夠?qū)崿F(xiàn)應(yīng)用主動推送呢?讓官方去支持這個幾乎是不可能,所以慣性思維讓我第一想到這個解決方案定時請求API,對比上次狀態(tài)作出通知。然后這種做法實在是在Low而且低效了,而且如果構(gòu)建時間短于你的輪詢時間,就會無法捕獲到狀態(tài)的變化了。
不過有個好消息是,目前很多平臺都支持了Webhook,開發(fā)者通過自定義回調(diào)函數(shù)的方式來獲取一些事件的消息,DaoCloud是支持鏡像構(gòu)建和持續(xù)集成的事件通知的,所以通過這個我們起碼能實時獲取到狀態(tài)的變化而不需要去輪詢API接口了,只需要將消息轉(zhuǎn)發(fā)給客戶端就可以了。
最后一個問題是通過什么方式來接收服務(wù)端的消息了,我沒有去看過任何關(guān)于Mac平臺上如何關(guān)于推送的資料(之前一個為了實現(xiàn)iOS應(yīng)用的推送,各種什么證書啊什么的折騰死了,Android就好太多了),畢竟我們用的是Electron,所以只需要使用提供JavaScript SDK的推送服務(wù)即可,之前做客戶一般都是使用了 極光推送、小米推送、百度推送* 等等,但這些一律都只是支持Android和iOS,而且目前只發(fā)現(xiàn)國內(nèi)只有云巴(不是廣告,不是軟文,后面有強力吐槽)提供了JavaScript,畢竟這此公司的定位不一樣。
云巴的JS-SDK是基于socket.io實現(xiàn)的,當(dāng)然也是可以支持Electron或者NW.js這種框架啦,而且在使用上和Web的沒有任何的不同。
現(xiàn)在開始
首先基于 electron-boilerplate 腳手架搭建項目的基本目錄結(jié)構(gòu),以下是daocloud-plus已經(jīng)按需整理好的目錄結(jié)構(gòu)
.
├── CHANGELOGS.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
│ ├── app.html
│ ├── app.js
│ ├── background.js
│ ├── components
│ ├── env.js
│ ├── helpers
│ ├── images
│ ├── node_modules
│ ├── package.json
│ ├── stylesheets
│ └── vendor
├── build
├── config
├── gulpfile.js
├── node_modules
├── package.json
├── releases
├── resources
└── tasks
客戶端
客戶端這邊需要生成一個別名(為了保證不重復(fù)這里使用了UUID)并且訂閱即可。
DaoCloud那邊只需要添加些Webhook即可
示例:http://daocloud-plus.blankapp.org/b131a88748f84b3f956839d3e9879baf
編寫相關(guān)消息接收代碼
/app/app.html
...
<!-- 引入云巴 JS SDK -->
<script src="./vendor/yunba/yunba-js-sdk.js"></script>
<script src="./vendor/yunba/socket.io-1.3.5.js"></script>
...
/app/app.js
...
// 從 localStorage 獲取別名,如果不存在則創(chuàng)建
var yunba_alias = localStorage.getItem('yunba_alias');
if (!yunba_alias) {
yunba_alias = uuid.v4();
yunba_alias = replaceall("-", "", yunba_alias);
localStorage.setItem('yunba_alias', yunba_alias);
}
// 初始化云巴SDK
yunba.init(function (success) {
if (success) {
// 連接服務(wù)器
yunba.connect(function (success, msg) {
if (success) {
// 設(shè)置別名,成功后服務(wù)端的消息將會在set_message_cb方法接收
yunba.set_alias({'alias': yunba_alias}, function (data) {
if (data.success) {
console.log('別名:' + yunba_alias + " 設(shè)置成功");
} else {
console.log(data.msg);
}
});
} else {
console.error(msg);
}
});
} else {
console.error(msg);
}
});
// 云巴消息監(jiān)聽
yunba.set_message_cb(function (data) {
console.log(data);
// 創(chuàng)建一個通知
var notification = new Notification('DaoCloud Plus', {
body: data.msg
});
});
...
服務(wù)端
服務(wù)端要做的事情就更加簡單了,接收Webhook的發(fā)送過來的數(shù)據(jù),通過云巴的REST接口發(fā)送給客戶端即可,這里為了快速使用了 Laravel 框架,為什么這么簡單的一個事情還要使用一個框架,那是因為我對PHP不熟,不想折騰~~
使用 laravel 創(chuàng)建 daocloud-plus-notifier 項目
$ larave new daocloud-plus-notifier
編寫相關(guān)消息推送代碼
/app/Http/routes.php
...
// 配置路由
// 示例:http://daocloud-plus.blankapp.org/b131a88748f84b3f956839d3e9879baf
Route::post('/{alias}', 'NotifierController@webhook');
...
/app/Http/Controllers/NotifierController.php
<?php
namespace App\Http\Controllers;
use GuzzleHttp\Client;
use Validator;
use Lang;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class NotifierController extends Controller
{
protected function webhook(Request $request, $alias)
{
$name = $request->input('name');
$build = $request->input('build');
if (!$build) {
return $this->failure();
}
// 根據(jù) build_type 和 status 組裝消息
$msg = Lang::get('daocloud.' . $build['build_type'] . '_' . strtolower($build['status']), ['name' => $name]);
// 向別名發(fā)送消息,通過 env 方法獲取到云巴的 AppKey 和 SecretKey
$client = new Client();
$response = $client->request('GET', 'http://rest.yunba.io:8080', [
'query' => [
'method' => 'publish_to_alias',
'appkey' => env('YUNBA_APPKEY', ''),
'seckey' => env('YUNBA_SECRET_KEY', ''),
'alias' => $alias,
'msg' => $msg
]
]);
if ($response->getStatusCode() == 200) {
return $this->success();
}
return $this->failure();
}
}
編碼完成
到此編碼工作已經(jīng)完成,代碼比較簡單,但是已經(jīng)實現(xiàn)了給 Electron 程序添加了消息通知功能了。
頭腦風(fēng)暴
通過Electron+Webhook+云巴就可以快速實現(xiàn)了一個實用的Mac應(yīng)用,其實通過Webhook可能做的事情還有很多很多,例如做一個基于Webhook的通知中心(哈哈,我竟然嫌現(xiàn)在的通知還不夠多啊~)等等
相關(guān)文章
項目地址
吐槽一下云巴
不提供包依賴管理工具的支持
我不太清楚目前的公司開發(fā)有沒有使用依賴管理工具,但是我個人認(rèn)為直接以文件的方式引入SDK的方式實在是太Low并且低效了
例如Android,我只需要在build.gradle文件添加
compile 'com.squareup.retrofit2:retrofit:2.0.2'
例如iOS,只需要在Podfile添加一行
pod 'AFNetworking', '~> 3.0'
例如NPM,只需要執(zhí)行一行命令
$ npm install lowdb --save
例如PHP,同樣只需要一行命令
$ composer require fzaninotto/faker
等等...
然而,國內(nèi)能提供包依賴管理工具支持的實在是少得可憐~~~
過于業(yè)余的接口命名規(guī)范
表示無法理解使用 publish2 這種命名~~
功能點相關(guān)概念重疊
在云巴的SDK里,alias 是基于 topic 來實現(xiàn)的,但是文檔并沒有說明,如果 alias 完全是基于 topic 的,那 alias 存在的意義是什么?
創(chuàng)建新應(yīng)用時必須填寫Android包名
以目前個人的理解,云巴不同于目前市面那些移動應(yīng)用推送平臺,并不局限于移動應(yīng)用,但是在后臺創(chuàng)建應(yīng)用的時候為什么必須讓我填寫Android的包名?
運行提供官方提供的Demo過于麻煩
Android 的 Demo 可不可以直接用AndroidStudio來寫啊?
有時候運行一個Demo的時候都要花上幾個小時~~~
[建議] 為開發(fā)者創(chuàng)造使用場景
云巴這個平臺個人感覺還是很優(yōu)秀的(僅限提供的實時數(shù)據(jù)交換服務(wù)),可以做的事情太多了,但是官方給我們展現(xiàn)出的一些使用場景太少了,而且在這個推送市場如此飽和的市場,很難讓我下定決心去選擇使用在自己的項目上。這個時候官方應(yīng)該為開發(fā)者創(chuàng)造更多的使用場景~~
以上吐槽同樣適用于國內(nèi)其他提供開發(fā)者服務(wù)的平臺
為什么要吐槽
我們使用第三方提供的服務(wù)是為了什么?就是為了能夠快速實現(xiàn)我需要的功能,然而大部分的服務(wù)提供商提供給開發(fā)者的包括SDK、文檔往往是和快速實現(xiàn)背道而馳的,往往在很多項目中,我們使用到的僅僅是一個很小的功能,但卻要進(jìn)行非常復(fù)雜的配置等等。
關(guān)于我
如果你對這個項目或者這篇文章感興趣,歡迎 Follow 我