くまのがっこう神経衰弱バトルのSNS投稿の作り方をご紹介します。スコアとランクとアイテムを画像にしてTwitterへ投稿しています。Lineはテキストのみ。FacebookはSDKを入れないと投稿できないようでしたので今回は見送っています。
iOS、Androidとネイティブ連携をする為に以下の3つのファイルを追加します。
SnsLauncher.h (iOS、Android共通のヘッダーファイル)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#ifndef SnsLauncher_h #define SnsLauncher_h #include "cocos2d.h" class SnsLauncher { public: static void openTW(const char* msg, const char* img); static void openFB(const char* msg, const char* img); static void openLN(const char* msg, const char* img); }; #endif |
SnsLauncher.mm (iOSのネイティブ連携用のファイル)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include "SnsLauncher.h" #import <Social/Social.h> #import <UIKit/UIKit.h> void SnsLauncher::openTW(const char* msg, const char* img) { if([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) { NSString* message = [NSString stringWithUTF8String:msg]; NSString* image = [NSString stringWithUTF8String:img]; UIViewController *myViewController = [UIApplication sharedApplication].keyWindow.rootViewController; SLComposeViewController *vc = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; [vc setInitialText: message]; [vc addImage:[UIImage imageWithContentsOfFile:image]]; [myViewController presentViewController:vc animated:YES completion:nil]; } } void SnsLauncher::openFB(const char* msg, const char* img) { // 未実装 } void SnsLauncher::openLN(const char* msg, const char* img) { NSString* message = [NSString stringWithUTF8String:msg]; NSString* image = [NSString stringWithUTF8String:img]; UIImage* imageData = [UIImage imageWithContentsOfFile:image]; UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; [pasteboard setData:UIImagePNGRepresentation(imageData) forPasteboardType:@"public.png"]; // Lineの場合はテキストか画像どちらかしか投稿できません NSString *LINEUrlString = [NSString stringWithFormat:@"line://msg/image/%@", pasteboard.name]; //NSString *LINEUrlString = [NSString stringWithFormat:@"line://msg/text/%@", message]; if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:LINEUrlString]]) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:LINEUrlString]]; } } |
SnsLauncher.cpp (Androidのネイティブ連携用のファイル)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include "SnsLauncher.h" #include <jni.h> #include "platform/android/jni/JniHelper.h" #define JNICLASSNAME "org/cocos2dx/cpp/AppActivity" USING_NS_CC; void SnsLauncher::openTW(const char* msg, const char* img) { JniMethodInfo mi; if(JniHelper::getStaticMethodInfo(mi, JNICLASSNAME, "openTW", "(Ljava/lang/String;Ljava/lang/String;)V")) { jstring jstrMsg = mi.env->NewStringUTF(msg); jstring jstrImg = mi.env->NewStringUTF(img); mi.env->CallStaticVoidMethod(mi.classID , mi.methodID, jstrMsg, jstrImg); mi.env->DeleteLocalRef(jstrMsg); mi.env->DeleteLocalRef(jstrImg); mi.env->DeleteLocalRef(mi.classID); } } void SnsLauncher::openFB(const char* msg, const char* img) { // 未実装 } void SnsLauncher::openLN(const char* msg, const char* img) { JniMethodInfo mi; if(JniHelper::getStaticMethodInfo(mi, JNICLASSNAME, "openLN", "(Ljava/lang/String;Ljava/lang/String;)V")) { jstring jstrMsg = mi.env->NewStringUTF(msg); jstring jstrImg = mi.env->NewStringUTF(img); mi.env->CallStaticVoidMethod(mi.classID , mi.methodID, jstrMsg, jstrImg); mi.env->DeleteLocalRef(jstrMsg); mi.env->DeleteLocalRef(jstrImg); mi.env->DeleteLocalRef(mi.classID); } } |
SnsLauncher.cppはiOSのビルドの対象にしないために、ファイルを追加する際にAdd to targetsのチェックを外してください。
次に投稿する画像を生成してSnsLauncherを呼び出すところです。
HelloWorldScene.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" USING_NS_CC; class HelloWorld : public cocos2d::Layer { private: // SNSの種類を定義 enum SnsType { TW, FB, LN }; // SNS画面を表示する関数 void openSnsTW(Ref* sender); void openSnsLN(Ref* sender); void openSns(SnsType sns, std::string msg); // メッセージをURLエンコードする関数 std::string urlEncode(std::string &str); public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(HelloWorld); }; #endif // __HELLOWORLD_SCENE_H__ |
HelloWorldScene.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include "HelloWorldScene.h" #include "SnsLauncher.h" USING_NS_CC; // テクスチャーのタグを定義 #define TAG_TEXTURE_SNS 100 // テクスチャーを保存するファイルをデバイス毎に設定 #if(CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #define SHARE_FILE "sns.png" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #define SHARE_FILE "share/sns.png" #endif Scene* HelloWorld::createScene() { auto scene = Scene::create(); auto layer = HelloWorld::create(); scene->addChild(layer); return scene; } bool HelloWorld::init() { if ( !Layer::init() ) { return false; } // テキストボタンを表示 auto buttonTW = MenuItemFont::create("Twitter", CC_CALLBACK_1(HelloWorld::openSnsTW, this)); auto buttonLN = MenuItemFont::create("Line", CC_CALLBACK_1(HelloWorld::openSnsLN, this)); auto menu = cocos2d::Menu::create(buttonTW, buttonLN, NULL); menu->setPosition(Point(250, 160)); menu->alignItemsHorizontallyWithPadding(100.0); this->addChild(menu); /* SNSに投稿する画像を生成 ----------------------------------------------------- */ // テクスチャを生成 RenderTexture* texScore = RenderTexture::create(480, 320); texScore->setPosition(300, 320); texScore->setTag(TAG_TEXTURE_SNS); // 画面上に0.8倍で表示 texScore->setScale(0.8); this->addChild(texScore); // テクスチャに画像を追加 texScore->begin(); auto imageBg = Sprite::create("HelloWorld.png"); imageBg->setPosition(Point(240, 160)); imageBg->visit(); auto image1 = Sprite::create("CloseNormal.png"); image1->setPosition(Point(60, 100)); image1->visit(); auto image2 = Sprite::create("CloseSelected.png"); image2->setPosition(Point(120, 100)); image2->visit(); texScore->end(); return true; } void HelloWorld::openSnsTW(Ref* sender) { openSns(TW, "こんにちは Twitter"); } void HelloWorld::openSnsLN(Ref* sender) { openSns(LN, "こんにちは Line"); } void HelloWorld::openSns(SnsType sns, std::string msg) { RenderTexture* texture = (RenderTexture*)this->getChildByTag(TAG_TEXTURE_SNS); texture->saveToFile(SHARE_FILE, Image::Format::PNG, true, [&,sns,msg](RenderTexture* rt, const std::string& path){ if (sns == TW) { SnsLauncher::openTW(msg.c_str(), path.c_str()); } if (sns == FB) { // 未実装 } if (sns == LN) { SnsLauncher::openLN(msg.c_str(), path.c_str()); } }); } |
ここでの注意点はテクスチャに画像を追加する際にretain()するかどうかです。この実装ではretain()するとメモリリークを起こしたのでretain()しませんでした。必ずXcodeのデバッグナビゲータを使ってメモリの使用状況を確認しましょう。
1 2 3 4 5 |
// このようにretain()するとメモリリークする auto image1 = Sprite::create("CloseNormal.png"); image1->retain(); image1->setPosition(Point(60, 100)); image1->visit(); |
iOSの場合はSocial.frameworkを追加すれば完了です。
Androidの場合は以下の設定を追加します。
proj.android/jni/Android.mk
1 2 3 4 5 |
# SnsLauncher.cppを追加 LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../Classes/AppDelegate.cpp \ ../../Classes/SnsLauncher.cpp \ ../../Classes/HelloWorldScene.cpp |
proj.android/src/org/cocos2dx/cpp/AppActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
package org.cocos2dx.cpp; import org.cocos2dx.lib.Cocos2dxActivity; import java.io.*; import android.support.v4.content.FileProvider; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Build; import android.net.Uri; public class AppActivity extends Cocos2dxActivity { private static Cocos2dxActivity me = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); me = this; // ファイル共有をするディレクトリを作成 File sharedDirectory = new File(me.getFilesDir(), "share"); sharedDirectory.mkdirs(); } static { System.loadLibrary("cocos2dcpp"); } /* sns ----------------------------------------------------- */ // twitter public static void openTW(String msg, String img) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setPackage("com.twitter.android"); intent.setType("image/png"); intent.putExtra(Intent.EXTRA_TEXT, msg); File sharedFile = new File(img); Uri contentUri = FileProvider.getUriForFile(me, "com.gameshonen.hello.fileprovider", sharedFile); intent.putExtra(Intent.EXTRA_STREAM, contentUri); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); try { me.startActivity(intent); } catch (android.content.ActivityNotFoundException e) { Intent intent2 = new Intent( Intent.ACTION_VIEW, Uri.parse("http://twitter.com/intent/tweet?text=" + msg)); me.startActivity(intent2); } } // face book public static void openFB(String msg, String img) { // 未実装 } // line public static void openLN(String msg, String img) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.setPackage("jp.naver.line.android"); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, msg); try { me.startActivity(intent); } catch (android.content.ActivityNotFoundException e) { Intent intent2 = new Intent( Intent.ACTION_VIEW, Uri.parse("http://line.me/R/msg/text/?" + msg)); me.startActivity(intent2); } } } |
今回は処理をAppActivity.javaに直接書きました。AppActivity.javaを継承するクラスを作るやり方もネットで紹介されていますので調べてみてください。
Twitterなどの他のアプリケーションと画像ファイルを共有する為にFileProviderの設定を追加します。
proj.android/AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<application android:label="@string/app_name" android:icon="@drawable/icon"> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.gameshonen.hello.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> </application> |
android:authorities=”com.gameshonen.hello.fileprovider” を自分のアプリケーションのpackage名.fileproviderへ書き換えてください。
proj.android/res/xml/filepaths.xml を新規に追加します。
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="share" path="share/"/> </paths> |
android-support-v4.jarをリンクして使えるようにします。一番簡単な方法はsdk/extras/android/support/v4/android-support-v4.jarをproj.android/libsへコピーすると使えるようになります。