Unityからネィティブプラグインを使いTwitterに投稿して、ツィートしたら何かを行う

引き続きネィティブ周りのど素人が苦戦しながら調べてみました。
基本的に[前回](http://qiita.com/okuhiiro/items/1aaec487d1ab8b086095)の続きです。
環境なども同じです。

# どういうことか
筆者はゲーム開発会社にて、ご飯を食べているので
「Twitterでつぶやいてくれたら何かあげるよ！」
みたいな感じが実装したかったのです。

Twitterに投稿するサンプルはググれば結構でてくるのですが
そこでツィートしたか？していないのか？の検知がなかなか見つからなかったので実装してみました。
ちなみにiOSの方法はググれば結構でてきたので、それを参考にしています。
苦戦したのはほとんどがAndroidだったりします。

# 実装
## Unity
Hierarchy、Game画面こんな感じです。
「Button」が「ツィートする」のボタン
「CallBackText」が「ツィートしてません」のテキスト
「TwitterController」が処理を行うスクリプト
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/17192/89755256-3985-e0e2-69d5-82845338c809.png)
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/f49e7c74-7403-92f3-db30-f13d890cca2b.png">

```csharp:TwitterController
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Runtime.InteropServices;

public class TwitterController : MonoBehaviour {
	public Text callBackText;

#if UNITY_IOS
    [DllImport("__Internal")]
    static extern void Twitter();
#endif

	public void OnTwitter()
	{
#if UNITY_EDITOR
        Debug.Log("UnityEditorでは使用できません");
#elif UNITY_ANDROID
		// パッケージ名 + クラス名を引数にする.
        AndroidJavaClass plugin = new AndroidJavaClass("okuhiiro.twitter.Twitter");
		// そのクラスのメソッドを指定する.
		// 引数があるの場合は、第2引数以降がそのメソッドの第1引数に該当する.
        plugin.CallStatic("LaunchTwitterActivity");

#elif UNITY_IOS
        Twitter();
#endif
	}

	public void OnTwitterResult(string str)
	{
		callBackText.text = str;
	}
}
```

## Android
### javaソース

UnityからCallされるクラスです。
パッケージ名 + クラス名は適宜置き換えてください。

```java:Twitter.java
package okuhiiro.twitter;

import android.app.Activity;
import android.content.Intent;
import com.unity3d.player.UnityPlayer;

public class Twitter {
    // TwitterのActivityを起動する.
    public static void LaunchTwitterActivity() {
        Intent intent = new Intent();
        final Activity activity = UnityPlayer.currentActivity;

        intent.setAction(Intent.ACTION_MAIN);
        intent.setClassName(activity, "okuhiiro.twitter.TwitterActivity");

        activity.startActivity(intent);
    }
}
```

上記のjavaからCallされるActivityクラスです。
startActivityForResultを使わないとツィートしたかどうか検知できなかったので
Activityを起動するという方法をとっています。

```java:
package okuhiiro.twitter;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;

import com.unity3d.player.UnityPlayer;

import java.util.List;

public class TwitterActivity extends Activity {

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        tweet();
    }

    // ツィートする.
    private void tweet() {
        // ツィートするデフォルトの文字列.
        String s = "hogehoge #hashtag" + System.getProperty("line.separator") + "http://aaa";

        Intent tweetIntent = new Intent(Intent.ACTION_SEND);
        tweetIntent.putExtra(Intent.EXTRA_TEXT, s);
        tweetIntent.setType("text/plain");

        // Androidにインストールされているパッケージをリストで取得？.
        PackageManager packManager = getPackageManager();
        List<ResolveInfo> resolvedInfoList = packManager.queryIntentActivities(
                tweetIntent,
                PackageManager.MATCH_DEFAULT_ONLY
        );

        // Twitterのパッケージ + クラス名をセットする.
        boolean resolved = false;
        for(ResolveInfo resolveInfo: resolvedInfoList){
            if(resolveInfo.activityInfo.packageName.startsWith("com.twitter.android")){
                tweetIntent.setClassName(
                        resolveInfo.activityInfo.packageName,
                        resolveInfo.activityInfo.name );
                resolved = true;
                break;
            }
        }

        // Twitterアプリがインストールされている場合.
        if(resolved)
        {
            startActivityForResult(tweetIntent, 1);
        }
        // Twitterアプリがインストールされていない場合.
        else
        {
            UnityPlayer.UnitySendMessage("TwitterController", "OnTwitterResult", "アプリがないよ");
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // ツィートせず.
        if (resultCode == 0)
        {
            UnityPlayer.UnitySendMessage("TwitterController", "OnTwitterResult", "ツィートせず");
        }
        // ツィートした.
        else
        {
            UnityPlayer.UnitySendMessage("TwitterController", "OnTwitterResult", "ツィートしたよ");
        }

        finish();
    }
}
```

### AndroidManifest.xml
Activityを使う場合は記述が必要なようです。
パッケージ名とクラス名は、1文字1句間違いなくいれてください。地味にハマりました... :disappointed_relieved: 

UnityのAndroidManifestテンプレートは下記にありました。
C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk\AndroidManifest.xml
これに以下の追記を行い、「Plugins」-「Android」以下にコピーしました。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/17192/d5797d71-c1eb-dffd-2d6b-45846e31cf25.png)

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
	android:installLocation="preferExternal"
    android:versionCode="1"
    android:versionName="1.0">
    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:anyDensity="true"/>

    <application
		android:theme="@style/UnityThemeSelector"
		android:icon="@drawable/app_icon"
        android:label="@string/app_name"
        android:debuggable="true">
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>

        <!-- ここに追加しました -->
        <activity android:name="okuhiiro.twitter.TwitterActivity"
                  android:label="TwitterActivity"
                  android:configChanges="keyboard|keyboardHidden|orientation">
        </activity>
    </application>
</manifest>
```

## iOS
Androidと比べてシンプルです。
下記ファイルを「プラグインを配置するフォルダを作成」で作成した「iOS」の下にいれます。

```objc:twitter.mm
#import <QuartzCore/QuartzCore.h>
#import "Social/Social.h"

extern "C" {
    void Twitter() {
        NSString *_text = @"hogehoge #hashtag";
        NSString *_url = @"http://aaaa";

        SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];

        composeViewController.completionHandler = ^(SLComposeViewControllerResult res) {
            if (res == SLComposeViewControllerResultCancelled) {
                UnitySendMessage("TwitterController", "OnTwitterResult", "ツィートせず");
            }else if (res == SLComposeViewControllerResultDone) {
                UnitySendMessage("TwitterController", "OnTwitterResult", "ツィートしたよ");
            }
            [composeViewController dismissViewControllerAnimated:YES completion:nil];
        };

        if ([_text length] != 0) {
            [composeViewController setInitialText:_text];
        }

        if ([_url length] != 0) {
            [composeViewController addURL:[NSURL URLWithString:_url]];
        }

        [UnityGetGLViewController() presentViewController:composeViewController animated:YES completion:nil];
    }
}
```

XCode側で下記frameworkが必要です。
<img width="681" alt="スクリーンショット 2016-09-06 11.47.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/17192/b86390f8-4fb7-7a11-c3a5-c143b281245b.png">


# 表示
## Android
「ツィートする」ボタンの押下。アプリがインストールされていない場合。
真っ白な画面に...。ちょっとここはすぐActivity終了するなりしたほうが良さそうです。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/59f03f5a-2837-624f-323b-9e36d58534c4.png">
戻るボタン押下後
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/5e310094-5f60-7673-bba2-b41ddd73f409.png">

「ツィートする」ボタンの押下。アプリがインストールされているがログインしていない場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/7c90a53c-40b1-52de-2b0a-2f7976b08646.png">

「ツィートする」ボタンの押下。アプリがインストールされていてログインしている場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/dfb3def3-7a97-3e7a-062a-d8c5d0ec59fd.png">

ツィートせず戻ってきた場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/5560e6bb-81b6-ffdb-f5f0-c48c0529ac99.png">

ツィートしてきた場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/60c1859c-d17e-1e06-6f89-74a3db382c71.png">

## iOS
iOSの場合は、以下パターンで見てみました。
- アプリがインストールされていない + Twitterとアカウントが結びついていない 
- アプリがインストールされている + Twitterとアカウントが結びついていない
- アプリがインストールされている + Twitterとアカウントが結びついている

「ツィートする」ボタンの押下。
アプリがインストールされていない + Twitterとアカウントが結びついていない場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/6e0eb725-c98c-44ef-01e9-411dee1e5108.png">
「キャンセル」ボタンの押下。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/5560e6bb-81b6-ffdb-f5f0-c48c0529ac99.png">

「ツィートする」ボタンの押下。
アプリがインストールされている + Twitterとアカウントが結びついていない場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/6c26e999-5a82-cc37-bd0e-b515530654a0.png">
「OK」ボタンの押下。「投稿」ボタンが押せない感じになっていました。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/966f4d4d-f088-7893-b42c-b1324a948134.png">
「キャンセル」ボタンの押下。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/5560e6bb-81b6-ffdb-f5f0-c48c0529ac99.png">

「ツィートする」ボタンの押下。
アプリがインストールされている + Twitterとアカウントが結びついている場合。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/86b615f1-e3ab-a738-f08f-3b3258250141.png">
「投稿」ボタンの押下。
<img width="320" src="https://qiita-image-store.s3.amazonaws.com/0/17192/60c1859c-d17e-1e06-6f89-74a3db382c71.png">