Cocos2d-x 3.2でスクリーンショットを撮ってツイート

Cocos2d-x3.2で、スクリーンショットを撮るためのメソッドが実装されたので、
これを使ってスクリーンショットをツイートする機能を作ってみたのでメモ。

基本はこの記事と同じです。
Cocos2d-xで撮ったスクリーンショットをTwitterに添付してツイートできないか試してみた - おかひろの雑記

※2014/8/8 iOS6でツイート後に画面操作ができなくなる問題があったため、NativeCodeLauncher_objc.mmを修正しました。

今回使用したバージョン

  • Cocos2d-x 3.2


Cocos2d-xでスクリーンショットを撮る方法はこちらhttp://www.cocos2d-x.org/projects/cocos2d-x/wiki/How_to_save_a_screenshotを参考にしました。


ネイティブ連携
ツイートする内容に加え、画像ファイルのフルパスを一緒に渡すようにしています。

共通
NativeCodeLauncher.h

namespace Cocos2dExt {
    class NativeCodeLauncher
    {
    public:
		static void openTweetDialog(char const *tweet,char const *filePath);
    };
}

iOS
NativeCodeLauncher.mm

static void static_openTweetDialog(const char* tweet,const char* filePath)
{
        [NativeCodeLauncher openTweetDialog:[NSString stringWithUTF8String:tweet] filePath:[NSString stringWithUTF8String:filePath]];
}

namespace Cocos2dExt
{
        void NativeCodeLauncher::openTweetDialog(const char *tweet,const char *filePath)
        {
                static_openTweetDialog(tweet,filePath);
        }
}

NativeCodeLauncher_objc.h

@interface NativeCodeLauncher : NSObject

+(void)openTweetDialog:(NSString *)tweet filePath : (NSString *)filePath;

@end

NativeCodeLauncher_objc.mm
※2014/8/8 CompletionHandler内にdismissViewControllerAnimatedメソッドを追加。それに伴う修正。

@implementation NativeCodeLauncher

+(void)openTweetDialog:(NSString *)tweet filePath:(NSString *)filePath
{
	if([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
	{
		AppController *appController = (AppController *)[UIApplication sharedApplication].delegate;

		NSString *serviceType = SLServiceTypeTwitter;
		SLComposeViewController *composeCtl = [SLComposeViewController composeViewControllerForServiceType:serviceType];
		[composeCtl setInitialText:tweet];
		UIImage *image = [UIImage imageWithContentsOfFile:filePath];
		[composeCtl addImage:image];
		[composeCtl setCompletionHandler:^(SLComposeViewControllerResult result) {
			[appController.viewController dismissViewControllerAnimated:YES completion:nil];
			if (result == SLComposeViewControllerResultDone) {
				//投稿成功時の処理
				NSLog(@"ツイートしました");
			}
        	}];

        	[appController.viewController presentViewController:composeCtl animated:YES completion:nil];
	}
	else
	{
		tweet = [NSString stringWithFormat:@"http://twitter.com/home?status=%@",tweet];
		tweet = [tweet stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
		NSURL *url = [NSURL URLWithString:tweet];
		[[UIApplication sharedApplication] openURL:url];
	}
}

@end

iOSの場合は画像ファイルをUIImageに読み込むだけなので簡単です。
Social.frameworkを使う形に変更しました。


Android
NativeCodeLauncher.cpp

namespace Cocos2dExt
{
        void NativeCodeLauncher::openTweetDialog(char const* tweet,char const *filePath)
        {
                openTweetDialogJNI(tweet,filePath);
        }
}

NativeCodeLauncherJni.h

extern "C"
{
	extern void openTweetDialogJNI(char const* tweet,char const *filePath);
}

NativeCodeLauncherJni.cpp

...

#define CLASS_NAME "org/cocos2dx/cpp/AppActivity"

...

extern "C"
{

...

        void openTweetDialogJNI(char const* tweet,char const *filePath)
        {
                JniMethodInfo methodInfo;
        
                if (!getStaticMethodInfo(methodInfo, "openTweetDialog", "(Ljava/lang/String;Ljava/lang/String;)V"))
                {
                    return;
                }
        
                jstring tweetArg = methodInfo.env->NewStringUTF(tweet);
                jstring filePathArg = methodInfo.env->NewStringUTF(filePath);
                methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, tweetArg,filePathArg);
                methodInfo.env->DeleteLocalRef(tweetArg);
                methodInfo.env->DeleteLocalRef(filePathArg);
                methodInfo.env->DeleteLocalRef(methodInfo.classID);
        }
}

AppActivity.java

public class AppActivity extends Cocos2dxActivity{

	private static Activity me = null;
	
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		
		me = this;
	}
	
    static {
         System.loadLibrary("game");
    }
    
    // JNIから呼び出すメソッド
    public static void openTweetDialog(String tweet,String filePath)
    {
        final String path = filePath;
        final String tweetMessage = tweet; 
        
        me.runOnUiThread(new Runnable(){
                @Override
                public void run()
                {
                        File f = new File(path);
                        
                        byte[] data;
                                try
                                {
                                        data = readFileToByte(path);
                                }
                                catch(Exception e)
                                {
                                        Log.e("Debug", e.getMessage());
                                        return;
                                }
                                
                                File savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
                                File saveFile = new File(savePath,"screenshot.jpeg");
                                
                                if(!savePath.exists())
                                {
                                        savePath.mkdir();
                                }
                                
                                FileOutputStream fos = null;
                                
                                try
                                {
                                        fos = new FileOutputStream(saveFile);
                                        fos.write(data);
                                        fos.close();
                                }
                                catch(Exception e)
                                {
                                        Log.e("Debug", e.getMessage());
                                        return ;
                                }
                        
                                Uri uri = Uri.fromFile(saveFile);
                
                                Intent it = new Intent(Intent.ACTION_SEND);
                                it.putExtra(Intent.EXTRA_SUBJECT, "");
                                it.putExtra(Intent.EXTRA_TEXT, tweetMessage);
                                it.putExtra(Intent.EXTRA_STREAM,uri);
                                it.setType("image/jpeg");
               
                                me.startActivity(Intent.createChooser(it,"共有"));
                }
        });
    }

    private static byte[] readFileToByte(String filePath) throws Exception
    {
                byte[] b = new byte[1];
                FileInputStream fis = new FileInputStream(filePath);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                while (fis.read(b) > 0) {
                        baos.write(b);
                }
                baos.close();
                fis.close();
                b = baos.toByteArray();
        
                return b;
    }
}

画像ファイルを外部ストレージに一旦コピーしています。
そのため、AndroidManifest.xmlパーミッションが必要になります。

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


呼び出し

	utils::captureScreen([&](bool succeed,const std::string &fileName){
		// ツイート
		if(succeed)
		{
			// スクリーンショット保存成功
			Cocos2dExt::NativeCodeLauncher::openTweetDialog(”ツイートメッセージ”,fileName.c_str());
		}
		else
		{
			// スクリーンショット保存失敗
			
		}
	}, "screenshot.jpg");

スクリーンショットを撮った後にコールバックされるようなので、その中でツイートの準備を行います。