[Facebook開發] 如何時時追蹤安裝/退出你的應用程式的使用者?

用facebooker開發好了一個ROR在facebook上的應用後,如果想知道目前某人現在是否安裝了你的程式,當他連上有建立Session的時候,我們用User#has_added_app可以知道他是否安裝了程式。如果把他的user id 存在local的資料庫裡,那麼你就可以知道目前所有"安裝了"你應用程式的使用者了。 不過,如果使用者在某個時間刪除掉了你的應用程式,也就是說他退出了,由於退出時沒有建立與ap間的session,我們不能用has_added_app來了解狀況,並刪除local資料庫的資料。使用者有進有出,時間久了,你的local資料庫上的資料就不準確了。若有做排名的列表,就可能出現幽靈人,明明已經沒裝你的應用,卻仍高掛第一名。
評論
評論

看到 Robert Shedd 的 這篇部落格 ,提到這個問題,整理一下分享給大家,相關的 code 也是引用自該文章。

基本問題 -- 因為 facebook 沒給安裝你應用的用戶清單,沒辦法精準掌握現有用戶

這裡假設你已經用 RoR+Facebooker 開發了幾個應用,如果還沒,可以閱讀:

那麼,用 facebooker 開發好了一個 ROR 在 facebook 上的應用後,如果想知道目前某人現在是否安裝了你的程式,當他連上有建立 Session 的時候,我們用 User#has_added_app 可以知道他是否安裝了程式。如果把他的 user id 存在 local 的資料庫裡,那麼你就可以知道目前所有"安裝了"你應用程式的使用者了。

不過,如果使用者在某個時間刪除掉了你的應用程式,也就是說他退出了,由於退出時沒有建立與 ap 間的 session,我們不能用 has_added_app 來了解狀況,並刪除 local 資料庫的資料。使用者有進有出,時間久了,你的 local 資料庫上的資料就不準確了。若有做排名的列表,就可能出現幽靈人,明明已經沒裝你的應用,卻仍高掛第一名。

解決方法 -- 使用 post_authorize 與 post_deauthorize

針對這樣的需求,facebook 提供了 post_authorize 與 post_deauthorize 兩個 callback,註冊了應用跟移除應用都可以通知我們的 ap 一聲,在這個地方做些事情,那麼我們就能確保數據的一致性了。

首先,Robert 建議另開一個 Controller,另外就是要注意要確認 authenticity token,程式碼範例如下:

class CallbacksController < ApplicationController   skip_before_filter :ensure_app_installed, :except => :post_authorize   skip_before_filter :verify_authenticity_token    def post_authorize     if request.post?       #做些事情,例如存資料庫       render :nothing => true     end   end    def post_deauthorize     if request.post?       #做些事情,例如刪除資料       render :nothing => true     end   end  end

進階注意-進一步確認加入/退出請求實際來自 Facebook 平台
以上程式碼已經可以了,可以解決使用者新增與退出應用時,我們能精準掌握他的狀態的問題了。不過,我們仍得注意另一個問題,就是這個動作是否來自 facebook 平台,免得被其他人透過其他方式觸發了。在上述的程式碼裡加上這段檢查,就變成了:

class CallbacksController < ApplicationController   skip_before_filter :ensure_app_installed, :except => :post_authorize   skip_before_filter :verify_authenticity_token    def post_authorize     if request.post?       if verify_uninstall_signature         #將使用者的 has_app 設成 1       end     end     render :nothing => true   end    def post_deauthorize     if request.post?       if verify_uninstall_signature         #把使用者的 has_app 設成 0       end     end     render :nothing => true   end    private       #參考了 http://wiki.developers.facebook.com/index.php/Post-Remove_URL       def verify_uninstall_signature         signature = ''         keys = params.keys.sort         keys.each do |key|           next if key == 'fb_sig'           next unless key.include?('fb_sig')           key_name = key.gsub('fb_sig_', '')           signature += key_name           signature += '='           signature += params[key]         end          signature += FACEBOOK_YAML['secret_key']         calculated_sig = Digest::MD5.hexdigest(signature)          if calculated_sig != params[:fb_sig]           logger.warn "\nWARNING :: potential spoofing :: expected signatures did not match"           logger.info "\nSignature (fb_sig param from facebook) :: #{params[:fb_sig]}"           logger.info "\nSignature String (pre-hash) :: #{signature}"           logger.info "\nMD5 Hashed Sig :: #{calculated_sig}"            #check to see if ip variables are nil           if not request.env['HTTP_X_FORWARDED_FOR'].nil? and not request.env['HTTP_X_REAL_IP'].nil?             ip = request.env['HTTP_X_FORWARDED_FOR'] || request.env['HTTP_X_REAL_IP']           else             ip = request.remote_ip           end            logger.info "\nRemote IP :: #{ip}"           return false         else           #logger.warn "\n\nSUCCESS!! Signatures matched.\n"         end         return true       end  end

其中要注意的是關於 FACEBOOK_YAML[‘secret_key’] 的這行,密碼金鑰要定義在 environment.rb:

    #load facebooker configuration for usage     facebook_config = File.join(RAILS_ROOT, 'config', 'facebooker.yml')     FACEBOOK_YAML = YAML::load(ERB.new(File.read(facebook_config)).result)[RAILS_ENV]

這樣,就可以準確掌握你的應用程式中真正的活躍者了!Happy Coding!