2014年10月13日 星期一

Facebook Login for Android v2.1 中文


一、 Android 環境以及Facebook SDK

  1. 首先你應該有Android的開發環境,如果還沒有,請至官方網站下載:http://developer.android.com/sdk/index.html
  2. 下載FaceBook SDK:https://developers.facebook.com/docs/android/downloads,目前最新版本為3.18.1:


  3. 將上一步驟下載的壓縮檔解壓縮之後,匯入至Eclipse:[File] -> [Import] -> [Existing Projects into Workspace] -> 選擇解壓縮的資料夾 -> 勾選FacebookSDK,並且勾選 Copy projects into workspace。

  4. 對FacebookSDK 右鍵 → properties →選擇 Android,如果沒有勾選,請勾選目前Android 的SDK版本,並檢查Is Library是否有打勾:

二、 建立新專案

  1. 建立新專案:開一個新的android專案。這邊須注意:由於FacebookSDK底下的lib資料夾也有一份android-support-v4.jar,所以若是有衝突,可以把其他地方(例如:appcompat_v7的lib資料夾)的android-support-v4.jar取代掉FacebookSDK底下的lib資料夾裡面的jar檔。
  2. 加入FacebookSDK Library:對著剛剛新增的專案右鍵 → Properties → 點選 Add → 增加FacebookSDK:

三、 建立新的Facebook App:

  1. 首先登入到Facebook 開發者網頁:https://developers.facebook.com/。如果沒有開發者帳號,請先申請。
  1. 點選App → Add a New App:
    1. 選擇Android:

    2. 輸入想要的App名稱:

    3. 在接下來的畫面,選擇完類別之後,按下確定:

    4. 接下來拉到畫面最下面,輸入package名稱,以及預設的Activity名稱:

    5. 下一步,我們需要填寫App的Hash Key,讓Facebook知道是不是同一個Android App。
      1. 首先下載OpenSSL:http://sourceforge.net/projects/gnuwin32/files/openssl/0.9.8h-1/openssl-0.9.8h-1-bin.zip/download?use_mirror=nchc
      2. 將下載下來的壓縮檔解壓縮,並且把bin資料夾底下的openssl.exe複製到你JAVA的bin資料夾裡面 (例如:C:\Program Files (x86)\Java\jre7\bin )。
      3. 點選開始功能表,輸入cmd,如下圖:


        接下來對著cmd.exe按右鍵,選擇以系統管理員身分執行。

      4. 輸入:keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
        執行成功會如下圖所示:

      5. 將產生的key複製,並且貼到Development Key Hash的欄位,然後按下下一步。

    6. 接下來看到這個畫面代表Facebook的App已經建立完成。

四、 App基本設置

  1. 加入app_id到string如下圖:


    其中你的app_id可以在你的Facebook App頁面找到:
    1. 增加上網的權限:打開AndroidManifest.xml → Add → 選擇Uses Permission → Name輸入android.permission.INTERNET。

    2. 切換 Application 頁面,新增Meta Data 項目,Name輸入:com.facebook.sdk.ApplicationId,Value輸入:@string/app_id:

    3. 新增Activity,Name輸入com.facebook.LoginActivity:

五、 修改App來完成登入的功能

  1. 繼承FragmentActivity:將原本的MainActivity extends Activity 改為 MainActivity extends FragmentActivity
    1. 新增類別MainFragment:新增一個類別MainFragment 繼承Fragment,並且在onCreateView裡面,使用activity_main的layout,程式碼如下圖所示:

    2. 加上登入按鈕:打開activity_main.xml,首先將原本的RelativeLayout改為LinearLayout,之後再把com.facebook.widget.LoginButton的按鈕加上去,最後的結果如下圖:

    3. 定義一個MainFragment的變數mainFragment:

    4. 修改onCreate function如下圖:

    5. 新增onActivityResult function:因為當按下登入按鈕的時候,會跳到LoginActivity,直到使用者登入或取消登入之後,才會跳回來MainActivity,所以我們需要覆寫這個function來記錄登入結果的Session:

    6. 執行結果:左圖為登入前;右圖為登入後:


六、 改用UiLifecycleHelper管理Session

  1. 首先建立處理登入登出的function:
    private
    void onSessionStateChange(Session session,
    SessionState
    state,

    Exception exception)
    {
    if
    (state.isOpened())
    {
    Log.i("state", "Logged in...");

    }
    else
    if
    (state.isClosed())
    {

    Log.i("state", "Logged out...");

    }
    }
    1. 建立callback function:
      private
      Session.StatusCallback callback =
      new
      Session.StatusCallback()
      {

      @Override

      public
      void call(Session session,
      SessionState state,
      Exception exception)
      {
      onSessionStateChange(session, state, exception);

      }
      };

    2. 建立UiLifecycleHelper變數:
      private
      UiLifecycleHelper uiHelper;

    3. 之後在onCreate function最後面加入底下兩行程式碼以初始化:
      uiHelper =
      new
      UiLifecycleHelper(MainActivity.this, callback);
      uiHelper.onCreate(savedInstanceState);

    4. 覆寫onCreate(), onResume(), onPause(), onDestroy(), onActivityResult() 以及 onSaveInstanceState() function,注意舊的onActivityResult要砍掉:

      @Override

      public
      void onResume()
      {

      super.onResume();
      // For scenarios where the main activity is launched and user

      // session is not null, the session state change notification

      // may not be triggered. Trigger it if it's open/closed.

      Session session =
      Session.getActiveSession();

      if
      (session !=
      null
      &&

      (session.isOpened()
      || session.isClosed())
      )
      {
      onSessionStateChange(session, session.getState(),
      null);

      }
      uiHelper.onResume();
      }

      @Override
      public
      void onActivityResult(int requestCode,
      int resultCode,
      Intent data)
      {

      super.onActivityResult(requestCode, resultCode, data);
      uiHelper.onActivityResult(requestCode, resultCode, data);
      }

      @Override
      public
      void onPause()
      {

      super.onPause();
      uiHelper.onPause();
      }

      @Override
      public
      void onDestroy()
      {

      super.onDestroy();
      uiHelper.onDestroy();
      }

      @Override
      public
      void onSaveInstanceState(Bundle outState)
      {

      super.onSaveInstanceState(outState);
      uiHelper.onSaveInstanceState(outState);
      }

    5. 修改到這邊,在執行App,就可以看到Log訊息有登入以及登出。

七、 使用API calls分享訊息:

  1. 增加發佈訊息的Button,如下圖:
    1. 接下來打開MainFragment程式碼原始檔,增加以下程式碼。
    2. 設定所需要的權限:
      private
      static
      final
      List<String> PERMISSIONS =
      Arrays.asList("publish_actions");

    3. 取得Button物件:
      Button shareBtn =
      (Button) view.findViewById(R.id.shareBtn);

    4. 檢查是否有權限的function:private
      boolean isSubsetOf(Collection<String> subset,
      Collection<String> superset)
      {

      for
      (String
      string
      : subset)
      {

      if
      (!superset.contains(string))
      {

      return
      false;

      }

      }

      return
      true;
      }

    5. 設定OnClickListener的內容:
      Session session =
      Session.getActiveSession();

      if
      (session !=
      null){

      //
      檢查是否有發佈權限

      List<String> permissions = session.getPermissions();

      if
      (!isSubsetOf(PERMISSIONS, permissions))
      {

      Session.NewPermissionsRequest newPermissionsRequest =
      new
      Session

      .NewPermissionsRequest(this, PERMISSIONS);
           session.requestNewPublishPermissions(newPermissionsRequest);

      return;

      }


      //
      設定發佈內容

      Bundle postParams =
      new
      Bundle();
      postParams.putString("message",
      "message");

      postParams.putString("name",
      " name ");
      postParams.putString("caption",
      " caption ");
      postParams.putString("description",
      " description ");
      postParams.putString("link",
      "https://developers.facebook.com/android");
      postParams.putString("picture",
      "https://raw.github.com/fbsamples/ios-3.x-howtos/master/Images/iossdk_logo.png");


      //
      設定發佈完成的callback

      Request.Callback callback=
      new
      Request.Callback()
      {

      public
      void onCompleted(Response response)
      {

      //
      取得發佈後的回應

      JSONObject graphResponse = response.getGraphObject().getInnerJSONObject();

      String postId =
      null;

      try
      {

      //
      取得發佈訊息的id
      postId = graphResponse.getString("id");

      }
      catch
      (JSONException e)
      {

      Log.i("JSON error :", e.getMessage());

      }

      FacebookRequestError error = response.getError();

      if
      (error !=
      null)
      {

      Toast.makeText(getActivity().getApplicationContext()
      ,"JSON error :" + error.getErrorMessage(),Toast.LENGTH_SHORT).show();

      }
      else
      {

      Toast.makeText(getActivity().getApplicationContext()
      ,"
      發佈成功,post id:" + postId,
      Toast.LENGTH_LONG).show();

      }

      }

      };


      //
      建立發佈request

      Request request =
      new
      Request(session,
      "me/feed", postParams,


      HttpMethod.POST, callback);

      //
      發佈訊息

      RequestAsyncTask task =
      new
      RequestAsyncTask(request);
      task.execute();

      }

    6. 發佈結果如下圖所示,請注意紅色框線的部分,分別對應到message、name…等:

八、 附註

當你忘記你的Android hash key又不想要重新產生一個的時候,可以使用以下的程式碼來幫助你取得你的Key。
PackageInfo info;


try{


info = getPackageManager().getPackageInfo("你的 package 名稱",PackageManager.GET_SIGNATURES);

for(Signature signature : info.signatures){

MessageDigest md;
md =MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
String KeyResult =new String(Base64.encode(md.digest(),0));
Log.e("my key is:", KeyResult);
}

}catch(NameNotFoundException e1){Log.e("name not found", e1.toString());

}catch(NoSuchAlgorithmException e){Log.e("no such an algorithm", e.toString());

}catch(Exception e){Log.e("exception", e.toString());}

沒有留言: