2013年12月11日 星期三

用Spark.function()自定REST API

前一篇有提到, TINKER API提供的四個功能都是很基本的, 如果只靠那四個, 那Spark cloud的負荷會很大, 想像一下, 如果說要做一台遙控車, 把馬達控制的程式都寫在遠端, 那需要發出多少命令? 如果REST API只是負責來發前進, 後退, 轉彎, 其他如該輸出多少給馬達或哪個腳位這類的邏輯留在core上面, 這樣的設計就會顯得合理多了
所幸Spark其實有考慮到這問題, 只是目前的文件真的很殘缺, 還真很難找到相關資料, 這問題的答案就是:
Spark.function()
這函數的作用在於對應core上的函數以及自定的REST API:
這函數第一個參數是REST命令的名字, 第二個則是處理這命令的函數, 相當簡單

(From: http://julianshen.tumblr.com/post/69702065061/spark-function-rest-api)

2013年12月8日 星期日

Spark core & Spark cloud

image

Spark core跟一般Arduino不同, 它並沒有一個在PC上的IDE供你寫及編譯程式, 這動作完全是在雲端, 開發者在Web IDE上攥寫程式, 之後server會去編譯並下載firmware到Spark core端執行

明明電腦跟Spark core都在眼前, 但程式卻不是在眼前編譯反而繞了一段路從Spark cloud下來, 感覺是有點多此一舉, 但其實Spark cloud的功能不僅於此, 它還提供了一個叫TINKER的服務

TINKER分為兩部分, 一個是手機上的TINKER APP

image

這App的用途就是讓你可以在不用寫任何一行程式的情況下, 就可以測試你的Spark core, 它背後的作法就是發送REST API, 也就是另一部分, 所謂的TINKER API, 到Spark cloud上, Spark cloud在把對應的命令轉到core上面, 由於core設定只要一打開就會連上網連到Spark cloud上, 因此可以用如此的方式控制它

因為可以透過TINKER API來控制core, 加上TINKER API也是公開的REST API, 因此, 我們未必要用Arduino的程式寫法來控制core, 我們也可以透過TINKER API用自己想用的程式語言來做開發

以以下的閃爍LED當做例子:

image

以傳統Arduino的寫法, 這樣一個程式(這範例應該老到掉牙了), 應該是這樣的:

跟C有點像, 當然啦,你不用期待它有啥多執行緒(Multiple threading), 或是啥事件驅動(event driven)等等東西可以用啦, 基本上它也是編譯好跑在Spark core上, core並沒有強大的運算能力跟複雜的硬體可以搞這麼複雜的東西, 有一點要注意的是, 這樣一個程式從Spark cloud燒錄到core去, 原本的TINKER就會被取代而失效, 必須由TINKER APP重新燒錄

至於說到TINKER API, 由於是REST API, 因此你可以用你習慣的語言去包裝, 不管是java, javascript, 或是go也好, 包裝它相當容易, 基本上目前也只有四個API: digitalwrite, digitalread, analogread, analogwrite

我包裝了Node.js跟Go可以使用的版本, 需要的人可以直接取用:

  1. Node.js module: https://github.com/julianshen/SparkCoreJs
  2. Go: https://github.com/julianshen/SparkGo

如果改用了Node.js或是Go, 那這個閃爍程式該如何寫?

Node.js:

這邊就可以把原本用"delay"的方式改用javascript中的setTimeout來實作

Go:

Go這邊則就是用了Tick

Access token跟device ID其實是可以去你的Web IDE上查到的

透過TINKER API, 這樣程式就不用一定得要"on board"去執行, 而且使用的程式語言也不會有侷限, 但缺點是, 首先要考慮到網路所造成的時間差問題, 另一個問題是, 現在提供的API像是digitalread這樣的API都非常的基本, 如果所有程式全部放在遠端, 遠端程式就必須要很頻繁的透過Spark cloud來發號司令, 如果連上Spark cloud的core越多, Spark cloud的負擔就相當可觀, 如果能提供custom command或custom api的方式, 把部分常態的邏輯變成在core端執行的內儲程序被呼叫, 或許可以減輕些Spark cloud的負擔

2013年12月7日 星期六

Spark core

image
前天回家發現一包順豐快遞的包裹, 心想, 我又沒去淘寶或對岸訂啥東西, 怎會有那邊來的包裹, 拿起來仔細一看, 這不是我之前在Kickstarter上Back那個叫Spark core的project嗎? (http://www.kickstarter.com/projects/sparkdevices/spark-core-wi-fi-for-everything-arduino-compatible?ref=home_social)
雖然依稀記得前幾天收到它開始出貨的消息, 可是後來完全忘了這一回事了, 這也是目前我第一個也是唯一在Kickstarter上back的東西
這是一個很有趣的產品, 也完全開放, open source, https://github.com/spark , 一開始看到盒子就讓我有點些許驚艷的感覺, 一打開, 原來這這麼小一片(還附片麵包版, 真是貼心), 用的則是TI CC3000MOD
image
這顆Chip有個比較有趣的功能就是 Smart Config (http://processors.wiki.ti.com/index.php/CC3000_Smart_Config), 有點不是很了它背後的機制, 不過這機制讓Spark core很容易的就可以設定好Wifi, Spark core本身沒任何的介面, 所以在設定Wifi hotspot跟Wifi密碼是一個大問題, Smart Config解決了這個問題, 所以你可以在手機上很輕易的輸入你要用的hotspot跟密碼, 接著Spark core就很神奇的連上hotspot, 然後連上Spark cloud, 這之間, Spark core根本也不需要跟你的手機透過藍芽或任何方式先連線, 不過手機這時候是必須使用Wifi而不是連上3G, 對於這種小型裝置來說, 這的確是一個很方便的方式
Spark core還有一個蠻聰明的部分, 那就是Spark cloud, 當他連上wifi時, 他就會嘗試連上Spark cloud, 在第一次設定時, 會先嘗試做註冊的動作, 把Spark core跟你的Spark帳號連結在一起, 不過我一開始不是很順利, 看起來Spark core已經順利連上Spark cloud, 但卻一直沒跟我帳號連結在一起, 這動作搞了我兩天, 多虧熱心的CEO Zach耐心的幫我查問題, 最後透過手動的方式把這搞定了
Spark cloud讓你可以利用他的Web IDE去寫firmware, 然後download到Spark core執行, 甚至, 你也可以不用寫任何程式, 直接透過他的Tinker API (REST), 去對你Spark core上的腳位做如digitalWrite之類的動作, 所以是可以把複雜的邏輯放在遠端
整體來說, 這是蠻有趣的產品, 蠻期待看他的未來的

2013年10月22日 星期二

悲劇,mbpr螢幕摔破了





悲劇,mbpr螢幕摔破了




via Tumblr http://julianshen.tumblr.com/post/64842280400

2013年10月21日 星期一

New toy





New toy




via Tumblr http://julianshen.tumblr.com/post/64674934723

2013年10月19日 星期六

[筆記] Android library project和manifestmerger.enabled

Android library project是為了解決Android開發中在不同專案間分享原始碼以及資源檔(resource)而出現的, 傳統的jar並未考慮資源檔的問題, 因此便需要靠Android library project來解決


目前, Android library project已經被廣泛運用, 舉凡ActionbarSherlock, Facebook Android SDK, 很多都已採用這形式


不過現在一般用法還是比較廣泛應用在跟UI相關這類的應用上, 這也合理, 這類的應用常需要包含原始碼和資源檔, 不過它也適合在其他應用上, 舉個例子(好吧, 這例子有點不清不楚), 我們也有可能需要讓所有使用某個library project的應用程式自動加上一個Intent Receiver, 假設這receiver實作上是固定的, 並不需要使用的應用程式自行去繼承, 或是, 我們希望某個Activity的實作是被連結到各個應用程式中, 這類應用使用Android library project也是可以辦到的


這類的應用, 通常還需要在AndroidManifest裡宣告, 除了receiver, activity, 也有可能加上一些service, 甚至是permission, 正常來說, 在建置使用了Android library project的專案時, library project裡的AndroidManifest的內容並不會合併到最後的AndroidManifest裡, 以致於, 雖然在library project內這些都被宣告了, 但成品內可能無法被使用, 這解法也很單純, 只要在應用程式(不是library project)的project.properties裡加上:


manifestmerger.enabled = true


Manifest merger似乎存在有一段時間了, 但似乎也沒看到啥正式的官方文件, 不過目前這方法是可行的就是了




via Tumblr http://julianshen.tumblr.com/post/64537710342

2013年9月18日 星期三

City of bones

想說最近有電影,宣傳的好像不錯一樣,就先來看一下小說,兩天內就拼完了三集,這還後面還有六集呀….


看完三集後,老實說不會想再看下去了,所謂的奇幻不過就是搞個吸血鬼狼人,闇影獵人之類的老梗外,沒啥太大的想像空間,扣除這些後就是…..灑夠狗血囉…..隱瞞,欺騙,背叛,三角習題,愛上的人結果是親妹妹(哥哥)想不出還有沒再多比這些更狗血的老梗了


天呀,我居然還看完三集!




via Tumblr http://julianshen.tumblr.com/post/61584538969

2013年9月15日 星期日

漢堡先生





漢堡先生




via Tumblr http://julianshen.tumblr.com/post/61289688682

2013年8月21日 星期三

[筆記] Google Drive API兩三事: App data, 靜態網頁連結

颱風天, 適合寫點東西, 所以就把上次的PinterestRSSAggregator加上發佈到Google Drive功能, 第一次碰Google drive api, 不過還好Google已經有了一個node.js的module: https://github.com/google/google-api-nodejs-client,省去了重刻Google API的功(這module還頗有趣的, 利用了Google discovery API, 支援了相當多Google API, 但實際上各API的細節的實作卻不在這module之中), 不過一開始還是在Google drive上碰到了一些問題:
  1. 想說要存個設定檔, 但檔案如果可以被使用者看到, 就會有機會被他砍了
  2. 因為是要發佈rss檔, 所以最好可以有一靜態連結
  3. Google drive是允許在同一目錄有同名的檔案的, 這似乎跟Dropbox不一樣, 它真正獨一無二的識別是id不是檔名, 所以要更新某個檔案還得先找到它的id, 有點小麻煩
第一項的解法還蠻簡單, 只要使用app data就好, 這目錄比較單純, 它的id就叫做"appdata"(真是夠怪了, 這個id是固定的, 但使用者的根目錄的id卻不是, 還得先用about去取得), 我用它實作了一個放設定的(參考這, AppConfig), 放在這目錄的好處是不會被使用者看到並刪除掉, 但要注意的一點是, 取得auth token時所做的認證用的scope必須包含"https://www.googleapis.com/auth/drive.appdata"

至於第二項的作法就是建立一個public folder, 並取得這目錄的webViewLink, 比如說是"https://www.googledrive.com/host/0B5rbRldWhe82WjhURVdkSzUxTjA/", 這樣你在這目錄下建的檔案, 例如 julianshen.rss 就可以用 "https://www.googledrive.com/host/0B5rbRldWhe82WjhURVdkSzUxTjA/julianshen.rss" 這連結來存取

2013年8月14日 星期三

看著海寫程式會不會太宅點? - PinterestRSSAggregator


陽光....跟沙灘呀......真是好風景呀....躺著寫程式真不錯 (其實在顧包包)

昨天上飛機前, 把這兩天晚上寫的東西, PinterestRSSAggregator, 在上飛機之前放上了github....趁現在來補一些內容

會寫這東西的緣起在於這篇: http://nickinglis.com/index.php/blog/item/how-to-get-your-pinterest-rss-feed

Pinterest目前沒API, 這RSS也只能取得一個人最近的資訊, 但常常我們要看的不會是自己去pin的, 而是自己所follow的人pin的最新資訊, 所以這樣的RSS用處就嫌少了點, 所以想說如果可以把自己所follow的全部集結成一個rss應該會很不錯, 因此就寫了這些東西

一開始碰到的問題點是, 沒API, 怎抓following的資訊? 從 http://pinterest.com/xxxx/following的網頁去解析, 似乎每個被follow的人的link都有userWrapper這class, 這或許是個出發點, 所以第一個版本做了一個直接去抓網頁回來解析抓出含有這class的連結....但是...失敗了...因為抓回來的靜態網頁, 最多只有十二個人的連結, 超過就抓不到, 網頁上要滑鼠捲到最下面才會再load出其他的

後來想到的方法就是利用CasperJS, 模擬捲頁捲到最後的行為, 再把所有followings都抓回來....喔耶....這招居然行的通....把所有rss 的url再用Google Feed API去抓內容(我懶得parse RSS了), 再用feed這module生成新的RSS....大功告成....接下來只要讓他固定一段時間跑一次, 就有一個土炮的Pinterest API用了... (還真heavy的API :( )

還要感謝一下同事 +kenshinn huang .....因為都是拿他帳號來作測試的.. XD

2013年6月28日 星期五

[Android] Retrofit + Signpost : 替Retrofit加上OAuth支援

看到Square發表的這個Retrofit - http://square.github.io/retrofit/ 蠻有趣的, 它的目的似乎是試圖的想要去簡化開發REST client, 開發者不用寫太多的邏輯, 只要寫一個Interface跟利用annotation就可以完成一個簡單的REST client:

public interface GitHubService {
  @GET("/users/{user}/repos")
  List<Repo> listRepos(@Path("user") String user);
}

因為開發者只需要寫interface和annotation, 實質上並不用寫任何的code, 真正實作的部份他用了Proxy class的技巧包裝起來了, 這作法讓我想起來很久之前我在之前的工作幫公司寫的一個legacy系統的wrapper, 那時有很多機器產生的interface, 如果人工一個個實作很浪費時間, Proxy class可以解決掉這一部分的問題, 同樣的在retrofit似乎也是想用這技巧節省實作

但可惜的是, 現在的retrofit並還沒加入OAuth的支援, 因此送出去的API部分並沒被oauth簽章過,不過所幸要解決這一部分也不難, 寫一個Client class搭配Signpost還是可以做到, 這邊範例繼承了OkClient(使用OkHttp) :



因為OkHttp也是一種HttpURLConnection, 因此Signpost搭配DefaultOAuthProvider和DefaultOAuthConsumer即可, 另外初始化RestAdapter時加上這個新的Client即可:

RestAdapter restAdapter = new RestAdapter.Builder() .setClient(new SignedOkClient(mConsumer))

2013年6月26日 星期三

[Android] 自定義View屬性

前一篇寫了一個自訂義的layout - SimpleCellLayout, 前一個版本的問題就是, 必須是寫程式把child view加進這個layout之中, 而且針對像是欄與行的數目也必須在程式裡設定, 並無法寫到layout xml中, 所以這次的目邊就是要讓這個layout可以像下面這樣用layout xml來擺佈:


在這範例之中, 用到幾個像是col, row, gapsize, cellX這些在原生Android並不存在的屬性, 為了這些屬性, 就需要定義一個attrs.xml在res/values目錄內, attrs.xml 裡面要定義的就是這些樣式描述屬性, 這邊定義了: 給SimpleCellLayout本身用的col(欄數), row(行數), gapsize(間距大小), 以及給他的Child views用的cellX(格子的橫軸位置), cellY(格子的縱軸位置), colspan(格子寬), rowspan(格子高), 除了gapsize我們需要的跟實際螢幕上的大小有關, 所以格式定義為dimension外(就是可以用3dp, 1px這類的值), 其他都是整數就可

這些屬性, 到時候就是要放在xml標籤內的屬性

要用到這些屬性, 需要先在tag裡面定義一個新的name space, 如同在前面範例寫的:

xmlns:celllayout="http://schemas.android.com/apk/res-auto"
文件內的範例大多是apk/後面接著package name, 不過Android Studio卻是建議使用"res-auto", 定義了這個name space後, 便可以在後面的tag內使用像是"celllayout:col"這樣的屬性了

那在layout內又要怎處理這些屬性? ViewGroup有兩個建構子所需要帶的參數含有AttributeSet, 基本上只要從這兩個建構子處理就好

這範例內的initFromAttributes就是用來從AttributeSet擷取這些屬性, 前面attrs.xml有定義stylable, 所以基本上有一堆相對應的Resource ID可以使用,這邊只處理了col, row, 和gapsize, 因為只有這三個屬性直接跟這layout相關, 至於這layout的child views該怎處理呢? 它就要靠LayoutParams了, 我在SimpleCellLayout內定義了一個CellLayoutParams, 基本上這類別也有一個建構子是用來處理AttributeSet的


這邊比較重要的就是要overwrite掉generateLayoutParams, 因為ViewGroup原有的generateLayoutParams實作的是回傳ViewGroup.LayoutParams, 他並不認得CellLayoutParams, 但SimpleCellLayout靠的是CellLayoutParams來儲存layout所需的資訊, 原本用程式來加入view的範例部份, 我是手動產生一個CellLayoutParams來給child view, 但如果是放在layout xml, 並無法指定要用哪個LayoutParams類別, 這時候就要靠generateLayoutParams了 有趣的是, 雖然是我自訂的layout, 但在我做完這些後, Android studio的UI編輯器, 卻知道怎去依據我的layout把元件畫到正確的位子上面:

2013年6月25日 星期二

[Android] 一個簡單的自製 layout - SimpleCellLayout

寫Android寫了這麼久, 才想到自己沒寫過custom layout, 剛剛花了點時間(主要時間還是花在跟Android studio和gradle搏鬥)寫了一個簡單的CellLayout (還很陽春) :

https://github.com/julianshen/SimpleCellLayout

寫custom layout還蠻簡單的, 在onMeasure決定自己和child views的大小, 在onLayout時把每個child views放到適當的位置, 目前還沒加入attibrtues的支援, 所以暫時還只能寫code自己把view加進去, 另外也還沒加檢查是不是會有重疊的views, 之後再來寫

這個layout跟GridView不同, 可以不用每個格子都是同一大小, 以下範例是把畫面劃成4x4的格子, 左上角的那張圖大小是2x2, 下方則是 4x2



2013年6月21日 星期五

[Android] 圓形大頭貼 - 使用Picasso的Transformation

現在不管是Google+也好, 或是Facebook (Home), 似乎都很喜歡用圓形的大頭貼像這樣 (左上角圖形,

但在server端存的大頭照其實都是都是方形的, 所以必須抓下來後再轉畫成圓的, 最近從網路抓圖的部分, 我還蠻喜歡用Picasso

沒啥別的原因, 就是它簡單, 雖然說, 它似乎還是有一些小小問題, 不過它可以用這樣短短一行解決圖檔下載並顯示到ImageView的一連串動作:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

不過, 簡單的代價可能在其他的地方來說彈性就不高了, 不過, 做這樣一個小玩意兒的彈性倒是還有, 在Picasso中, 可以實作Transformation把下載下來的圖檔再作一次後處理, 在它的網頁有一個CropSquareTransformation的範例, 圓形的大頭貼可以視為這一個的延伸:

這邊利用了BitmapShader重畫了一張圓形的大頭貼, 出來的結果就會像是這樣:


2013年6月20日 星期四

[Android] 一閃一閃亮晶晶的BlinkLayout

Androids Do Daydream裡有提到Romain Guy要他提(大概假的吧)在layout裡面放"<blink>"可以做到view閃爍的效果而不用寫到一行code

查了一下AOSP的原始碼也的確有這東西, 它是一個躲在LayoutInflater的一個叫BlinkLayout的東西, 這樣一來就可以配合TextClock (API Level 17)來做一個閃爍的時鐘了


不過, 這樣, 是整個TextClock在閃, 而不是像一般數字鐘一樣是只有":"閃, 如果要做到只有":"在閃, 那只好把"時"跟"分"給拆開, 像這樣:

2013年6月16日 星期日

[筆記][Android Studio]Git push

本想說有直接整合了Git, GitHub是件不錯的事, 沒想到要把新project push到remote git就栽了....

Android Studio/Intellij 似乎沒介面設定remote (搜尋了半天沒發現這種答案, 啃了半天的使用手冊也沒發現), 現在如果要把既有的project給匯出到遠端的git (如bitbucket), 就得利用command line (以bitbucket 為例):

  1. 在bitbucket上create一個新的project
  2. 在Android studio選"VCS"->"Import into version control"->"Create Git repository", 這樣就可以建立一個local的repository
  3. "VCS"->"Git"->"Add to VCS"
  4. "VCS"->"Git"->"Commit File"
  5. 到command line下切換到project目錄下"git remote add origin ssh://git@bitbucket.org/xxx/xxx.git"
  6. 回到Android studio, "VCS"->"Git"->"Push"
要注意的是, 如果你已經有一個remote repository,"VCS"->"Import into version control"->"Share project on GitHub"會失敗


2013年6月15日 星期六

[筆記] Android Studio, Gradle & Native libraries

最近試用Android studio開發, 可能有些習慣被以往Eclipse慣壞了, 剛剛發現放在libs/底下的東西不像以前會被自動建置到apk內, 有點小訝異, 對jar file來說, 可能還好不算太難, 在build.gradle的dependencies內補上一筆就夠了, 但對native library (jni)那些.so檔, 就沒辦法

用這樣解決了 Google了一下, 並且在Stack overflow上找到些解法來試, 可能因為Android studio跟Gradle Android plugin還一直在變化中, 在現在這版一直沒成功, 後來小改一下成底下這樣就成功了:


原本找到的解法是pkgTask.jniDir new File('build/native-libs') , 這樣會得到
> Directory 'build/native-libs' specified for property 'jniDir' does not exist.
把"new File"改成"file"就沒問題了,不過現在一切應該都還在開發中, 未來可能會有原生的native lib 支援也不一定, 未來可能這方法也不管用了吧

2013年4月2日 星期二

[Android] 列印到Android裝置

剛剛從Chrome要列印一份文件時, 發現一件有趣的事, 在選擇印表機時, 發現我的手機也在清單當中


這怎一回事? 難道可以從電腦"列印"文件到手機?

測了一下果然是如此, 在我的手機上會多了一份pdf, 內容就是由我的電腦列印過去的, 而且是透過Google Cloud Print, 打開Cloud Print的設定, 可以看到Print Jobs的確有我剛列印過去的


這功能需要有登入Cloud Print, 並且手機也要安裝Chrome才可以

不知道實不實用, 還蠻有趣的就是了


2013年4月1日 星期一

[Android dev] JsonReader

原本在Android下解析JSON內容,  大多用JSONObjectJSONArray, 這兩個是很簡單的JSON parser, 只要將字串(String)傳入即可

不過, 這跟在用DOM解析XML是有類似的問題, 解析文件是一氣呵成, 必須要把所有內容先走過一遍, 也需要更多的記憶體來儲存, 這對於解析較大的文件是一個大問題, 必須要花費更多時間和空間, 而且如果所需要的資料就算只是整份文件中間的一小部分, 還是得先把整份文件走完, 在XML, 可以用SAX來解決這問題, 但Android要到API level 11(Honeycomb) 才新增了JsonReader這個算是JSON界的SAX的解決方案

 JsonReader類似SAX, 也是一種streaming parser, 並不用一次讀出所有字串內容, 它要的只是個Reader, 但不太像SAX屬於事件驅動(event driven)的方式, 它應該比較像token consuming, 它定義了幾類基本的JsonToken,  它也有BEGIN(END)_OBJECT, BEGIN(END)_ARRAY這種類似SAX中startElement, endElement, 但卻沒類似SAX的startDocument

解析一個JSON物件的程式碼如下:

     {username:"Bob", age: 14, sex: "m"} 
     reader.beginObject();
     while (reader.hasNext()) {
       String name = reader.nextName();
       if (name.equals("username")) {
         username = reader.nextString();
       } else if (name.equals("age")) {
         followersCount = reader.nextInt();
       } else {
         reader.skipValue();
       }
     }
     reader.endObject();
解析一個物件, 要從beginObject開始(陣列則是beginArray), endObject結束, 接著透過一個while loop一個個走過這物件內所有的token, 說實在的, 不是很好debug,  你必須要先知道下一個要處理的token是啥類別, 以上面的例子為例, 物件內第一個token是"username", 這是一個JsonToken.NAME, 因此要用nextName來處理, 搞錯了就會出錯, 還不容易知道錯哪,  而上面那例子裡的"else"也是必須的, 拿掉的話, 在endObject就會出錯, 因為這段程式並沒去處理"sex", 因此處理完sex這個名字後, 並未消化掉"m"這個值(JsonToken.STRING), 而是直接endObject, 這會產生一個IllegalStateException

為了避免用了錯誤的方式處理下一個token, 可以先用peek()來看一下下一個要處理的種類

在可讀性上, 用JsonReader寫出的並不是很好, 但它卻適合來處理大的JSON文件, 或是像Twitter Streaming API這種幾乎無止盡的

這當然也不是只有在Android上有, Google也早把這也包含到GSON去了

2013年3月21日 星期四

可以用來取代Google Reader的另一個Google產品 - Currents (潮流同步)

最近科技界比較流行的戲碼是: Google要把Google Reader給送上斷頭台了

這齣戲有點輕肥皂劇的感覺, 先是Google公布要把Reader給喀嚓了, 再來就是一堆重度使用者叫苦連天, 一堆原本吃Google reader豆腐的服務跳出來說要接手實作替代方案, 緊接著是Google reader的Product manager 在Quora上爆料Google都把人抽去做Google+, 再來就是有重量級的部落格重炮轟擊Google關掉受歡迎的東西卻拿人力去開發沒用的東西(Google+), 對於這樣的評論, 個人是認為"言重了", 我自己本身的觀點跟這些是有點相反的, 不過我的觀點不主流, 這篇也不是為了談這個, 只是先行加點小小囉嗦... :P

Google Reader停了, 對原本的重度使用者以及使用到他的服務比如說feedly, 應該是重傷不少, 對我個人而言, 影響不大, 我在幾年前早把我消耗資訊的習慣, 從Reader轉到Twitter了, 個人認為Twitter也是一個很好的消化資訊的管道

不過, 先不管Reader和Twitter...你聽過Google有一個跟Reader同質性相當高的服務叫Google Currents嗎? 這是一個在這一年內(應該是吧)的新服務(中文譯名是有點矬):


目前除了有Android版本外, iOS上也是可以找的到

跟Google Reader不同的是, 它比較像Flipboard, 事先把新聞網站分類整理好讓使用者訂閱, 乍看之下是跟Google Reader不一樣的概念, 但是, 其實Google Reader訂閱的東西也是可以轉移到這邊來的

首先, 從"新增訂閱項目"開始

拉到最下面, 可以找到你原本就在Google Reader已訂閱的項目, 這時候你就可以把他們一個個加進來了


那可不可以加自定的RSS呢? 也不難, 這邊示範了怎樣加我自己Flickr的RSS, 搜尋"flickr julianshen", 馬上就找到它了, 我甚至還不用跑到Flickr網頁去找到那個RSS

再做另一個實驗, 搜尋我的名字"julianshen", 不但我的Flickr, 我的blog, 甚至是我的GitHub, Youtube, 都跑出來可以讓你去訂閱, 而且搜尋速度, 還蠻快的

當然也不是沒有缺點:

  1. 目前只有Android, iOS 版本並無PC或Web版本, 當然更無其他3rd party軟體
  2. 加進去的RSS都會被自動歸類, 大多被歸類在"資訊提供", 有些會被歸類的其他類別(比如說某些科技公司的新聞的RSS可能會被自動歸類到科技類), 沒辦法像Google Reader一樣自定目錄來分類, 也不能修改分類
  3. 沒辦法直接跟瀏覽器配合
不過這些好像對Google來說也不是啥複雜難做的吧

有兩個同質性那麼高的服務, 關掉其中一個也還蠻合理的啦, 賴到Google+頭上, 好像也有點無辜 XD




2013年3月13日 星期三

Twitter 1.1 API的Search不再是不需要Authentication的了

以往Twitter的search API是不需要任何認證, 也不需要設定啥App ID或啥consumer key的, 不過, 在API 1.1之後, 這就改了

因為1.1, search也列入rate limit的追蹤囉, 所以使用search API也要做認證(Authentication), 但由於search api的使用情境, 不見得一定需要使用者登入, 有些做資料分析的應用也有可能會用到, 所以強制用OAuth就有點不是很合理, 所幸, 除了用OAuth以外, 這類的API也可以使用Application-only authentication:


  1. 首先必須要用Basic Auth的方式取得token, 用consumer key當user name, consumer secret當password去呼叫/oauth2/token的API
    1. 使用POST
    2. 必須要有grant_type=client_credentials
  2. 成功的話就會得到access_token (注意token type為bearer)
  3. 使用這個token去呼叫API (search或其他不需要user login的API)
    1. 把token加在HTTP的Authentication header (像是: Authorization: Bearer AAAAAAAAAAAAAAAA )
    2. 一定要走SSL (https), 如果是非SSL會碰到"Bad Authentication data"的錯誤
以下是Sample code (使用Go):




2013年2月15日 星期五

[Mac] 在Qt中使用自訂的Info.plist

iOS和Mac OS的應用程式裡都有個info.plist放置著應用程式相關的設置, 用Qt開發Mac應用程式時, 這個檔是在編譯時自動產生, 因此幾乎是固定內容

但還是有需要在info.plist內加入額外的內容, 比如說Retina display的支援(NSHighResolutionCapable), 預設並沒有, 因此還是有需要做自訂的info.plist

作法並不難, 在專案檔(通常是 xxxx.pro)內加入下面的內容:
mac {
QMAKE_INFO_PLIST = XXXX.plist
}

mac {}內指得是, 這些內容只有針對mac os才有效, 而XXXX.plist則是你的Info.plist的範本檔名, 這個檔跟專案檔放在同一個目錄

XXXX.plist的內容則像這樣:

跟一般的Info.plist其實是一樣的, 我在這範例裡面加上了"NSHighResolutionCapable", 其餘都跟原先自動產生的內容是差不多的, 除了幾個關鍵內容用變數取代, 這邊變數都是以"@"包起來的, 比如說"@ICON@"就是應用程式的圖示

重新做一次qmake後, 下次編譯的Info.plist便會以這個檔案為範本產生了

2013年2月9日 星期六

讓Eclipse支援Retina Display

前陣子買了一台Retina display的mac book pro, 興沖沖的把一切都設定好後, 正很滿足的想要用這漂亮的畫面開始工作時, 一打開Eclipse後, 一整個傻眼, 字變糊變鋸齒, 看來Eclipse對Retina display並沒有很好的支援, 查詢過各方資料後, 所幸還有救(不然就想投奔到別的IDE去了)

1. 找到Eclipse, 在上面按右鍵選"顯示套件內容"

2. 找到Info.plist, 用Xcode開啟


3. 新增一個"High Resolution Capable", 並將其設成"YES"


2013年1月22日 星期二

[Android][筆記] BitmapShader

http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
這篇文章裡面使用到了BitmapShader做圓角的效果, 使用這方法, 如果drawRect的大小比原先大的話, 會根據Shader.TileMode來畫出不同的效果:

Shader.TileMode.CLAMP (效果: 尾端拉長) --

Shader.TileMode.MIRROR (效果: 鏡射) --

(畫面是我的小作業 - iTunes U for Android)