Parseを使ってソーシャルログイン&POSTまでやってみる

Moving On
http://blog.parse.com/announcements/moving-on/
Parseのサービスが終了してしまうそうなので、この記事はお墓行きですね…

#ParseのライブラリでFacebookとTwitterに投稿する

今回はあのプッシュ通知をいい感じに送ってくれる[Parse](https://parse.com/)のライブラリーを使って
FacebookとTwitterにログインして投稿するまでサンプルを紹介したいと思います。

# 下準備

まずは下準備です。
FacebookとTwitterを同時に進めて行きますが
片方だけでも大丈夫です。

## FacebookとTwitter共通

### Parseのライブラリーをビルドパスに通す

Parseのウェブサイトへ登録、ログインしてAndroid用のSDKをダウンロードします。
現在ではv1.3.9が最新版です。
Parse-1.3.9.zipというファイルがダウンロードされるので
それを解凍して「Parse-1.3.9.jar」をAndroidプロジェクトのlibsフォルダに突っ込んで
ビルドパスを通してあげます。
Twitter、Facebook共にParseのライブラリーは必要です。

## Twitter用

### Twitterアプリケーションの用意

[こちら](http://qiita.com/gabu/items/4a63e6b56dd50da1f528)を参考にTwitterアプリケーションを登録します。

## Facebook用

### Facebookアプリケーションの用意

[こことか](http://princesswell.rocketserver.jp/web-cheat-sheet/facebook-developers-application/)を参考にアプリ登録してください。

## FacebookSDKにビルドパスを通す

Facebookの方はParse単独では認証と投稿ができないので
別途FacebookSDKの準備が必要になります。
[FacebookのDevelopersサイト](https://developers.facebook.com/docs/android/getting-started/facebook-sdk-for-android/jp/)を参考にfacebookSDKにビルドパスを通してください。

# 認証から投稿までのソース

## Applicationクラスを作成する。
独自のApplicationクラスを作成してParseを初期化します。

```java:ApplicationSample

public class ApplicationSample extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //Parseの初期化
        Parse.initialize(this,"ParseのApllication ID","ParseのClient key");     
        //Twitterを使う場合
        ParseTwitterUtils.initialize("TwitterのConsumer key","TwitterのConsumer secret");
        //Facebookを使う場合
        ParseFacebookUtils.initialize("FacebookのAppID");
    }
}

```

##manifestファイルを編集する
applicationタグに先ほどの作成した「ApplicationSample」を指定するのと

```xml
 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
```

を追記します。

```xml:manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="parse.login.sample"
          android:versionCode="1"
          android:versionName="1.0">
    <uses-sdk android:minSdkVersion="15"/>
    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher"
            android:name=".ApplicationSample">
        <activity android:name=".Twitter"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

```

## Twitter認証と投稿するActivity

```java:Twitter
public class Twitter extends Activity {

    private Button btnAuth = null;
    private Button btnPost = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.twitter_layout);

        //認証するボタン
        btnAuth = (Button) findViewById(R.id.btnAuth);
        btnAuth.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginTwitter();
            }
        });

        //投稿するボタン
        btnPost = (Button) findViewById(R.id.btnPost);
        btnPost.setEnabled( ParseTwitterUtils.getTwitter().getAuthToken() != null );
        btnPost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if( ParseTwitterUtils.getTwitter().getAuthToken() != null ){
                    PostTask task = new PostTask();
                    task.execute();
                } else{
                    Toast.makeText(getApplicationContext(), "認証してない", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    //Twitterにログインする
    public void loginTwitter() {
        ParseTwitterUtils.logIn(this, new LogInCallback() {
            @Override
            public void done(ParseUser user, ParseException err) {
                if (user == null) {
                    Toast.makeText(getApplicationContext(), "NG", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(getApplicationContext(), "　OK", Toast.LENGTH_LONG).show();
                    btnPost.setEnabled(true);
                }
            }
        });
    }

    //「テスト」を投稿する
    class PostTask extends AsyncTask<String, Integer, Integer> {

        @Override
        protected Integer doInBackground(String... params) {
            HttpClient client = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost("https://api.twitter.com/1.1/statuses/update.json");
            List<NameValuePair> postParams = new ArrayList<NameValuePair>();
            HttpResponse response = null;
            try {
                postParams.add(new BasicNameValuePair("status", "テスト"));
                httpPost.setEntity(new UrlEncodedFormEntity(postParams, "UTF-8"));
                ParseTwitterUtils.getTwitter().signRequest(httpPost);
                response = client.execute(httpPost);
            } catch (ClientProtocolException e) {
            } catch (UnsupportedEncodingException e) {
            } catch (IOException e) {
            }
            return response.getStatusLine().getStatusCode();
        }

        @Override
        protected void onPostExecute(Integer statusCode) {
            super.onPostExecute(statusCode);
            if( statusCode == HttpURLConnection.HTTP_OK ){
                Toast.makeText(getApplicationContext(), "投稿完了", Toast.LENGTH_LONG).show();
            }else{
                Toast.makeText(getApplicationContext(), "失敗", Toast.LENGTH_LONG).show();
            }
        }
    }
}
```

特に必要ないと思われますが、レイアウトxmlです。ただボタンを2つ置いているだけです。

```xml:twitter_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
    <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Twitter認証"
            android:id="@+id/btnAuth" android:singleLine="false"/>
    <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="投稿"
            android:id="@+id/btnPost"/>
</LinearLayout>
```

これで「認証する」ボタンを押すとTwitterのログイン画面が立ち上がり。
認証完了後に「投稿する」ボタンを押すとTwitterに「テスト」が投稿されます。
認証と投稿を１つのActivityで楽に書けます。
ソースの量も比較的少なくて済むのではないでしょうか？

## Facebook認証と投稿するActivity

```java:Facebook

public class Facebook extends Activity {

    private Button btnReadPermissions = null;
    private Button btnPublishPermissions = null;
    private Button btnPost = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.facebook_layout);
        btnReadPermissions = (Button) findViewById(R.id.btnReadPermission);
        btnReadPermissions.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestReadPermissions();
            }
        });

        btnPublishPermissions = (Button) findViewById(R.id.btnPublishStream);
        btnPublishPermissions.setEnabled(false);
        btnPublishPermissions.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestPublishPermissions();
            }
        });

        btnPost = (Button) findViewById(R.id.btnPost);
        btnPost.setEnabled(false);
        btnPost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                postToFacebook();
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        ParseFacebookUtils.getSession().onActivityResult(this, requestCode, resultCode, data);
        if( ParseFacebookUtils.getSession().getPermissions().contains("publish_stream") ){
            ParseFacebookUtils.saveLatestSessionData(ParseUser.getCurrentUser());
            btnPost.setEnabled(true);
        }
    }

    //read_permissionを取得する
    public void requestReadPermissions() {
        ParseFacebookUtils.logIn(
                this, new LogInCallback() {
            @Override
            public void done(ParseUser user, ParseException err) {
                if (err == null) {
                    Toast.makeText(getApplicationContext(), "認証完了", Toast.LENGTH_LONG).show();
                    btnPublishPermissions.setEnabled(true);
                }
            }
        });
    }

    //publish_streamのpermissionを取得する
    public void requestPublishPermissions() {
        Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, Arrays.asList("publish_stream"));
        newPermissionsRequest.setDefaultAudience(SessionDefaultAudience.ONLY_ME);
        ParseFacebookUtils.getSession().requestNewPublishPermissions(newPermissionsRequest);
    }

    //Facebookへ「テスト」を投稿する
    public void postToFacebook() {
        Request request = Request.newStatusUpdateRequest(ParseFacebookUtils.getSession(), "テスト", new Request.Callback() {
            @Override
            public void onCompleted(Response response) {
                Toast.makeText(getApplicationContext(), " 投稿完了", Toast.LENGTH_LONG).show();
            }
        });
        request.executeAsync();
    }
}

```

facebookのActivityに使うレイアウトです。ボタンが３つ置いてあるだけです。

```xml:facebook_layout.xml
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ReadPermission"
            android:id="@+id/btnReadPermission" android:singleLine="false" android:layout_gravity="center"/>
    <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="PublishStream"
            android:id="@+id/btnPublishStream" android:singleLine="false" android:layout_gravity="center"/>
    <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="投稿"
            android:id="@+id/btnPost" android:layout_gravity="center"/>
</LinearLayout>
```

Facebookの方は先に「read_permission」を取得した後に
「publish_stream」のパーミッションを取得します。
先にpublish系のパーミッションを取得しようとすると、「先にread系のパーミッションを取れ」とexceptionを出してくるので注意です。

# 最後に
Parseは本当に便利ですね。
push通知だけでなく、TwitterやFacebookのSDKもいい感じにラップしてくれているので認証周りが楽に書けます。
今回TwitterやFacebookのアプリ登録や、FacebookSDKの導入などかなり端折ってしまいましたので
時間がある時に別途上げたいと思います。

参考になるかはわかりませんが今回のサンプルソースを[git](https://github.com/masahide318/ParseLogin)に上げておきました。