cocos2d-x-3.0beta2のプロジェクトをgradle化してみる(x-plugin検証<AdMob,twitter plugin編)

自メモ)
記事分割
 分割元:



さて実際のx-pluginを使ってみる。

一応中華依存サービスではなく、Androidで普通に使えそうなのは

  1. AdMob Plugin
  2. Twitter Plugin
    1. ただしIOSに関してはSocialFramework使ってない=>怪しいサードパーティ製(中華製?)=>使うの微妙 って話だったが。。



pluginをADTで使える形に修正)

想定は


irof
├── Classes
├── cocos2d
├──cocos/2d/platform/android/java/build.gradle //☆☆☆(cocosのJNIラッパー)
├──plugin
   ├──protocols/proj.android/build.gradle //☆☆☆☆(x-pluginのイ
ンターフェース)
   ├──plugins
    ├──admob/proj.android/build.gradle //◎
    ├──twitter/proj.android/build.gradle //◎
├── gradle //☆
├── gradlew //☆
├── gradlew.bat //☆
├── proj.android
├── build.gradle //☆☆☆
├── proj.ios_mac
├── proj.linux
├── proj.win32
├── Resources
├── settings.gradle //☆☆
└── build.gradle //☆☆
な形の予定。

 cocos2d-xの開発者の人は、ADTの最新でテストしてないのか
admob と twitter のlibrary-projectをimportして、実機転送すると落ちる

 理由は


AndroidManifest.xml
ForManifest.xml
bin
build.xml
gen
libs //<= なんも入ってない
local.properties
project.properties
res
sdk //<= GoogleAdMobAdsSdk.jar
src

    <!-- version-tag: 1 -->
    <import file="${plugin.dir}/tools/android/build_common.xml" />
</project>

で ant実行時にsdkフォルダのjarをclasspathに通すという馬鹿っぽい仕様がずっと放置。。
まあx-pluginでも更新かかってるのは、相変わらずJSBだけだしな。。(汗

微妙によくわからん
pythonスクリプトとかshellでsdkフォルダ見てるみたいなので

  • sdk/*.jar => libs/*.jar

にコピーを行っておく*1




  • cocos2d/plugin/plugins/admob/proj.android/build.gradle
  • cocos2d/plugin/plugins/twitter/proj.android/build.gradle
apply plugin: 'android-library'

dependencies {
    // libs/ にある *.jar を一括で追加する
    compile fileTree(dir: 'libs', include: '*.jar')
    //compile fileTree(dir: 'sdk', include: '*.jar') //ADT使わないからlibsにコピーしたくないよ的な人はこちら
    //compile "com.android.support:support-v4:${supportPackageVersion}"

    //library-projectから更に依存参照しているプロジェクトも記述
    compile project(':cocos2d/cocos/2d/platform/android/java')
    compile project(":cocos2d/plugin/protocols/proj.android")
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.1"

//ADT LIKE Source Location add start
	sourceSets {
    	main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
    	}
    }
//ADT LIKE Source Location add end

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 19
    }

    compileOptions {
        encoding = "UTF-8"
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}
  • cocos2d/plugin/protocols/proj.android/AndroidManifest.xml(修正)
  • cocos2d/plugin/plugins/admob/proj.android/AndroidManifest.xml (修正)
  • cocos2d/plugin/plugins/twitter/proj.android/AndroidManifest.xml (修正)

 各Pluginに入っているAndroidManifest.xml ですが
android gradle pluginのLintチェックのため 現在applicationタグがないと落ちる形です*2

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.cocos2dx.libAdsAdmob"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" />

	<application /> <!--ココ追記-->
</manifest>
  • settings.gradle(修正)
include ':proj.android',':cocos2d/cocos/2d/platform/android/java',':cocos2d/plugin/protocols/proj.android',':cocos2d/plugin/plugins/admob/proj.android',':cocos2d/plugin/plugins/twitter/proj.android'




◎pluginにパッチ、微修正をあてる)
現状の上記2つのpluginに関しても挙動が微妙な面があるのでpatchをあてる

  • admob
    • キーがコードにベタ書き
    • そのまま表示すると白余白等が出てしまっている*3
  • twitter
    • キーがコードにベタ書き
    • CALLBACK_URLもベタ書き
    • twitter自体はtweet後に日にちが経つと再検索しにくいのでtwitpicに対応しておく
  • admob


irof
├── Classes
├── cocos2d
├──plugin
   ├──protocols/proj.android
   ├──plugins
    ├──admob/proj.android
    ├──twitter/proj.android

    • cocos2d/plugin/protocols/proj.android
      • src/org/cocos2dx/plugin/AdsWrapper.java
//サイズ指定版の追加
public static void addAdView(WindowManager mWm, View adView,int width,int height,int pos) {
		WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
		mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
		mLayoutParams.width = width;
		mLayoutParams.height = height;
		mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
		
		switch (pos) {
		case POS_CENTER:
			mLayoutParams.gravity = Gravity.CENTER;
			break;
		case POS_TOP:
			mLayoutParams.gravity = Gravity.TOP;
			break;
		case POS_TOP_LEFT:
			mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
			break;
		case POS_TOP_RIGHT:
			mLayoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
			break;
		case POS_BOTTOM:
			mLayoutParams.gravity = Gravity.BOTTOM;
			break;
		case POS_BOTTOM_LEFT:
			mLayoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
			break;
		case POS_BOTTOM_RIGHT:
			mLayoutParams.gravity = Gravity.BOTTOM | Gravity.RIGHT;
			break;
		default:
			break;
		}
		mWm.addView(adView, mLayoutParams);
	}
    • cocos2d/plugin/plugins/admob/proj.android
      • res/values/ad_key.xml (追加)
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<!-- //adMob -->
	<string name="adUnitId"></string>
</resources>
    • cocos2d/plugin/plugins/admob/proj.android

最新のAdmobに差し替え

GoogleAdMobAdsSdk-6.4.1.jar
    • cocos2d/plugin/plugins/admob/proj.android
      • src/org/cocos2dx/plugin/AdsAdmob.java
/****************************************************************************
Copyright (c) 2012-2013 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
package org.cocos2dx.plugin;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;

import com.google.ads.*;
import com.google.ads.AdRequest.ErrorCode;

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.WindowManager;

public class AdsAdmob implements InterfaceAds {

	private static final String LOG_TAG = "AdsAdmob";
	private static Activity mContext = null;
	private static boolean bDebug = false;
	private static AdsAdmob mAdapter = null;

	private AdView adView = null;
	private String mPublishID = "";
	private Set<String> mTestDevices = null;
	private WindowManager mWm = null;

	private static final int ADMOB_SIZE_BANNER = 1;
	private static final int ADMOB_SIZE_IABMRect = 2;
	private static final int ADMOB_SIZE_IABBanner = 3;
	private static final int ADMOB_SIZE_IABLeaderboard = 4;
	private static final int ADMOB_SIZE_Skyscraper = 5;

	private static final int ADMOB_TYPE_BANNER = 1;
	private static final int ADMOB_TYPE_FULLSCREEN = 2;



	protected static void LogE(String msg, Exception e) {
		Log.e(LOG_TAG, msg, e);
		e.printStackTrace();
	}

	protected static void LogD(String msg) {
		if (bDebug) {
			Log.d(LOG_TAG, msg);
		}
	}

	public AdsAdmob(Context context) {
		mContext = (Activity) context;
		mAdapter = this;
		
//addAdView SizeSet mod stat
		m_r = mContext.getResources();
        android.util.DisplayMetrics metrics = new android.util.DisplayMetrics();
        mContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        m_density = (int)metrics.density;
	}
	
	private static android.content.res.Resources m_r = null;
	private static int m_density = 0;
	
	public static int dens(int val){
		return val * m_density;
	}
//addAdView SizeSet mod end

	@Override
	public void setDebugMode(boolean debug) {
		bDebug = debug;
	}

	@Override
	public String getSDKVersion() {
		//return "6.3.1";
		return "6.4.1";//SDK最新化したので
	}

	@Override
	public void configDeveloperInfo(Hashtable<String, String> devInfo) {
		try {
			mPublishID = devInfo.get("AdmobID");
//resource get key add start
			if(mPublishID==null){
				mPublishID = m_r.getString(org.cocos2dx.libAdsAdmob.R.string.adUnitId);
			}
//resource get key add end
			LogD("init AppInfo : " + mPublishID);
		} catch (Exception e) {
			LogE("initAppInfo, The format of appInfo is wrong", e);
		}
	}

	@Override
	public void showAds(Hashtable<String, String> info, int pos) {
	    try
	    {
	        String strType = info.get("AdmobType");
	        int adsType = Integer.parseInt(strType);

	        switch (adsType) {
	        case ADMOB_TYPE_BANNER:
	            {
	                String strSize = info.get("AdmobSizeEnum");
	                int sizeEnum = Integer.parseInt(strSize);
    	            showBannerAd(sizeEnum, pos);
                    break;
	            }
	        case ADMOB_TYPE_FULLSCREEN:
	            LogD("Now not support full screen view in Admob");
	            break;
	        default:
	            break;
	        }
	    } catch (Exception e) {
	        LogE("Error when show Ads ( " + info.toString() + " )", e);
	    }
	}

	@Override
	public void spendPoints(int points) {
		LogD("Admob not support spend points!");
	}

	@Override
	public void hideAds(Hashtable<String, String> info) {
	    try
        {
            String strType = info.get("AdmobType");
            int adsType = Integer.parseInt(strType);

            switch (adsType) {
            case ADMOB_TYPE_BANNER:
                hideBannerAd();
                break;
            case ADMOB_TYPE_FULLSCREEN:
                LogD("Now not support full screen view in Admob");
                break;
            default:
                break;
            }
        } catch (Exception e) {
            LogE("Error when hide Ads ( " + info.toString() + " )", e);
        }
	}

	private void showBannerAd(int sizeEnum, int pos) {
		final int curPos = pos;
		final int curSize = sizeEnum;

		PluginWrapper.runOnMainThread(new Runnable() {

			@Override
			public void run() {
				// destory the ad view before
				if (null != adView) {
					if (null != mWm) {
						mWm.removeView(adView);
					}
					adView.destroy();
					adView = null;
				}

				AdSize size = AdSize.BANNER;
				switch (curSize) {
				case AdsAdmob.ADMOB_SIZE_BANNER:
					size = AdSize.BANNER;
					break;
				case AdsAdmob.ADMOB_SIZE_IABMRect:
					size = AdSize.IAB_MRECT;
					break;
				case AdsAdmob.ADMOB_SIZE_IABBanner:
					size = AdSize.IAB_BANNER;
					break;
				case AdsAdmob.ADMOB_SIZE_IABLeaderboard:
					size = AdSize.IAB_LEADERBOARD;
					break;
				case AdsAdmob.ADMOB_SIZE_Skyscraper:
				    size = AdSize.IAB_WIDE_SKYSCRAPER;
				    break;
				default:
					break;
				}
				adView = new AdView(mContext, size, mPublishID);
				AdRequest req = new AdRequest();
				
				try {
					if (mTestDevices != null) {
						Iterator<String> ir = mTestDevices.iterator();
						while(ir.hasNext())
						{
							req.addTestDevice(ir.next());
						}
					}
				} catch (Exception e) {
					LogE("Error during add test device", e);
				}
				
				adView.loadAd(req);
				adView.setAdListener(new AdmobAdsListener());

				if (null == mWm) {
					mWm = (WindowManager) mContext.getSystemService("window");
				}
				
				//addAdView SizeSet mod stat
				if(size == AdSize.BANNER){
					AdsWrapper.addAdView(mWm, adView,dens(320),dens(50), curPos);
				}
				else{
					AdsWrapper.addAdView(mWm, adView, curPos);
				}
				//addAdView SizeSet mod end
			}
		});
	}

	private void hideBannerAd() {
		PluginWrapper.runOnMainThread(new Runnable() {
			@Override
			public void run() {
				if (null != adView) {
					if (null != mWm) {
						mWm.removeView(adView);
					}
					adView.destroy();
					adView = null;
				}
			}
		});
	}

	public void addTestDevice(String deviceID) {
		LogD("addTestDevice invoked : " + deviceID);
		if (null == mTestDevices) {
			mTestDevices = new HashSet<String>();
		}
		mTestDevices.add(deviceID);
	}

	private class AdmobAdsListener implements AdListener {

		@Override
		public void onDismissScreen(Ad arg0) {
			LogD("onDismissScreen invoked");
			AdsWrapper.onAdsResult(mAdapter, AdsWrapper.RESULT_CODE_AdsDismissed, "Ads view dismissed!");
		}

		@Override
		public void onFailedToReceiveAd(Ad arg0, ErrorCode arg1) {
			int errorNo = AdsWrapper.RESULT_CODE_UnknownError;
			String errorMsg = "Unknow error";
			switch (arg1) {
			case NETWORK_ERROR:
				errorNo =  AdsWrapper.RESULT_CODE_NetworkError;
				errorMsg = "Network error";
				break;
			case INVALID_REQUEST:
				errorNo = AdsWrapper.RESULT_CODE_NetworkError;
				errorMsg = "The ad request is invalid";
				break;
			case NO_FILL:
				errorMsg = "The ad request is successful, but no ad was returned due to lack of ad inventory.";
				break;
			default:
				break;
			}
			LogD("failed to receive ad : " + errorNo + " , " + errorMsg);
			AdsWrapper.onAdsResult(mAdapter, errorNo, errorMsg);
		}

		@Override
		public void onLeaveApplication(Ad arg0) {
			LogD("onLeaveApplication invoked");
		}

		@Override
		public void onPresentScreen(Ad arg0) {
			LogD("onPresentScreen invoked");
			AdsWrapper.onAdsResult(mAdapter, AdsWrapper.RESULT_CODE_AdsShown, "Ads view shown!");
		}

		@Override
		public void onReceiveAd(Ad arg0) {
			LogD("onReceiveAd invoked");
			AdsWrapper.onAdsResult(mAdapter, AdsWrapper.RESULT_CODE_AdsReceived, "Ads request received success!");
		}
	}

	@Override
	public String getPluginVersion() {
		return "0.2.0";
	}

    @Override
    public void queryPoints() {
        LogD("Admob not support query points!");
    }
}



irof
├── Classes
├── cocos2d
├──plugin
   ├──plugins
    ├──twitter/proj.android

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<!-- //SNS設定 -->
	<string name="consumar_key"></string>
	<string name="consumar_secret"></string>
	<string name="twitpic_api_key"></string>
	
	<string name="callback_scheme"></string>
	<string name="callback_host"></string>
</resources>

最新の twitter4j に差し替え

signpost-commonshttp4-1.2.1.1.jar
signpost-core-1.2.1.1.jar
signpost-jetty6-1.2.1.1.jar
twitter4j-core-3.0.6-SNAPSHOT.jar
twitter4j-media-support-3.0.6-SNAPSHOT.jar
twitter4j-spdy-support-3.0.5-SNAPSHOT.jar
/****************************************************************************
Copyright (c) 2012-2013 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
package org.cocos2dx.plugin;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.Hashtable;

import org.cocos2dx.libSocialTwitter.R;
import org.cocos2dx.plugin.TwitterApp.TwDialogListener;

import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import android.content.res.Resources;

public class ShareTwitter implements InterfaceShare {

	private static final String LOG_TAG = "ShareTwitter";
	private static Activity mContext = null;
	private static InterfaceShare mShareAdapter = null;
	protected static boolean bDebug = false;
	private static String CONSUMER_KEY="";
	private static String CONSUMER_SECRET="";
	private static String TWITPIC_API_KEY = "";//support twitpic
	
	private static TwitterApp mTwitter = null;
	private static boolean isInitialized = false;
	private static Hashtable<String, String> mShareInfo = null;
	

//append key start
	private final static String KEY_CONSUMER_KEY = "TwitterKey";
	private final static String KEY_CONSUMER_SECRET = "TwitterSecret";
	private final static String KEY_TWITPIC_API_KEY = "TwitPicAPIKey";
//append key end
	
	
	public final static String KEY_TEXT="SharedText";
	public final static String KEY_IMAGE_PATH = "SharedImagePath";
//append key start
	public final static String KEY_TEXT_PATH = "SharedTextPath";
//append key end

	private static boolean encode_f = false;//support encode test

	protected static void LogE(String msg, Exception e) {
		Log.e(LOG_TAG, msg, e);
		e.printStackTrace();
	}

	protected static void LogD(String msg) {
		if (bDebug) {
			Log.d(LOG_TAG, msg);
		}
	}

	public ShareTwitter(Context context) {
		mContext = (Activity) context;
		mShareAdapter = this;
		
		// from resouce key add start
		Resources m_r = mContext.getResources();
		CONSUMER_KEY = m_r.getString(R.string.consumar_key);
		CONSUMER_SECRET = m_r.getString(R.string.consumar_secret);
		TWITPIC_API_KEY = m_r.getString(R.string.twitpic_api_key);
		LogD("key : " + CONSUMER_KEY);
		LogD("secret : " + CONSUMER_SECRET);
		LogD("twitpic : " + TWITPIC_API_KEY);
		// from resouce key add end
	}
	

	@Override
	public void configDeveloperInfo(Hashtable<String, String> cpInfo) {
		LogD("initDeveloperInfo invoked " + cpInfo.toString());
		try {
			//一番上に持ってこないと連打で入るシーケンスもあるらしい
			if(isInitialized){
				return;
			}
			isInitialized = true;	
			//mod cpIfo from data add start
			String _CONSUMER_KEY= cpInfo.get(KEY_CONSUMER_KEY);
			if(_CONSUMER_KEY != null){
				CONSUMER_KEY = _CONSUMER_KEY;
			}
			String _CONSUMER_SECRET= cpInfo.get(KEY_CONSUMER_SECRET);
			if(_CONSUMER_SECRET != null){
				CONSUMER_SECRET = _CONSUMER_SECRET;
			}

			String _TWITPIC_API_KEY= cpInfo.get(KEY_TWITPIC_API_KEY);
			if(_TWITPIC_API_KEY != null){
				TWITPIC_API_KEY = _TWITPIC_API_KEY;
			}
			
			LogD("key : " + CONSUMER_KEY);
			LogD("secret : " + CONSUMER_SECRET);
			LogD("twitpic : " + TWITPIC_API_KEY);
			//mod cpIfo from data add end
			
			//support encode test
			try {
				encode_f = Boolean.valueOf(cpInfo.get("encode_flag"));
			} catch (Exception e) {
				encode_f = false;
			}

			
			
			PluginWrapper.runOnMainThread(new Runnable() {
				
				@Override
				public void run() {
					mTwitter =  new TwitterApp(PluginWrapper.getContext(), ShareTwitter.CONSUMER_KEY, ShareTwitter.CONSUMER_SECRET);
					mTwitter.setListener(mTwLoginDialogListener);
				}
			});
		} catch (Exception e) {
			LogE("Developer info is wrong!", e);
		}

	}

	@Override
	public void share(Hashtable<String, String> info) {
		LogD("share invoked " + info.toString());
		mShareInfo =  info;
		if (! networkReachable()) {
			shareResult(ShareWrapper.SHARERESULT_FAIL, "Network error!");
			return;
		}

		if (! isInitialized) {
			shareResult(ShareWrapper.SHARERESULT_FAIL, "Initialize failed!");
			return;
		}

		// need login
		if(!mTwitter.hasAccessToken()){
			PluginWrapper.runOnMainThread(new Runnable() {
				
				@Override
				public void run() {
					mTwitter.authorize();
				}
			});

			return;
		}
		
		PluginWrapper.runOnMainThread(new Runnable() {
			
			@Override
			public void run() {
				ShareTwitter.sendToTwitter();
			}
		});
	}

	@Override
	public void setDebugMode(boolean debug) {
		bDebug = debug;
	}

	@Override
	public String getSDKVersion() {
		return "3.0.6-SNAPSHOT";
	}

	private boolean networkReachable() {
		boolean bRet = false;
		try {
			ConnectivityManager conn = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo netInfo = conn.getActiveNetworkInfo();
			bRet = (null == netInfo) ? false : netInfo.isAvailable();
		} catch (Exception e) {
			LogE("Fail to check network status", e);
		}
		LogD("NetWork reachable : " + bRet);
		return bRet;
	}

	private static void shareResult(int ret, String msg) {
		ShareWrapper.onShareResult(mShareAdapter, ret, msg);
		LogD("ShareTwitter result : " + ret + " msg : " + msg);
	}

	private static final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
		
		@Override
		public void onError(int flag, String value) {
			LogD("Twitter connection failed!");
			shareResult(ShareWrapper.SHARERESULT_FAIL, value);			
		}
		
		@Override
		public void onComplete(String value) {
			ShareTwitter.sendToTwitter();
		}
	};

	private static void sendToTwitter() {
		String text = mShareInfo.get(KEY_TEXT);
		String imagePath = mShareInfo.get(KEY_IMAGE_PATH);
		String textPath = mShareInfo.get(KEY_TEXT_PATH);

		try {
			//ファイル添付型の場合の対応
			if (textPath != null) {
				File fn = mContext.getFileStreamPath(textPath);
				if (fn.exists()) {
					String lineBuffer = null;
					FileInputStream fis = null;
					StringBuilder sb = new StringBuilder();
					try {
						fis = mContext.openFileInput(textPath);
						BufferedReader reader = new BufferedReader(
								new InputStreamReader(fis, "UTF-8"));
						while ((lineBuffer = reader.readLine()) != null) {
							sb.append(lineBuffer);
						}
						text = sb.toString();
					} catch (Exception e) {
					}
				}
			}
			
			//文字がエンコードされている時
			if(encode_f){
				try{
					text = URLDecoder.decode(text,"utf-8");
				}
				catch(Exception ex){}
			}

			if (imagePath != null && imagePath.length() > 0) {
				if (ShareTwitter.TWITPIC_API_KEY != null
						&& !"".equals(ShareTwitter.TWITPIC_API_KEY)) {
					try {
						String url = mTwitter.updateStatusTwitPic(text,
								imagePath, ShareTwitter.TWITPIC_API_KEY);
						mTwitter.updateStatus(text + " " + url);
					} catch (Exception e) {
						mTwitter.updateStatus(text, imagePath);
					}
				} else {
					mTwitter.updateStatus(text, imagePath);
				}
			} else {
				mTwitter.updateStatus(text);
			}
			LogD("Posted to Twitter!");
			shareResult(ShareWrapper.SHARERESULT_SUCCESS, "Share succeed!");
		} catch (Exception e) {
			LogD("Post to Twitter failed!");
			shareResult(ShareWrapper.SHARERESULT_FAIL, "Unknown error!");
			e.printStackTrace();
		}
	}

	@Override
	public String getPluginVersion() {
		return "0.2.0";
	}
}
/**
 * @author Lorensius W. L. T <lorenz@londatiga.net>
 * 
 * http://www.londatiga.net
 */

package org.cocos2dx.plugin;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;

import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import twitter4j.StatusUpdate;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;

import twitter4j.conf.ConfigurationBuilder;
import twitter4j.media.ImageUploadFactory;
import twitter4j.media.MediaProvider;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Window;
import android.content.res.Resources;

public class TwitterApp {
	private Twitter mTwitter;
	private TwitterSession mSession;
	private AccessToken mAccessToken;
	private CommonsHttpOAuthConsumer mHttpOauthConsumer;
	private OAuthProvider mHttpOauthprovider;
	private String mConsumerKey;
	private String mSecretKey;
	private ProgressDialog mProgressDlg;
	private TwDialogListener mListener;
	private Context context;
	private boolean mInit = true;
	private static final String LOG_TAG = "TwitterApp";

//create callback_url add start
	//public static final String CALLBACK_URL = "twitterapp://connect";
	public static String CALLBACK_URL = "";
	public static final String CALLBACK_URL_FORMAT = "%s://%s";
//create callback_url add end
	
	protected static void LogE(String msg, Exception e) {
		Log.e(LOG_TAG, msg, e);
		e.printStackTrace();
	}

	protected static void LogD(String msg) {
		if (ShareTwitter.bDebug) {
			Log.d(LOG_TAG, msg);
		}
	}

	
	public TwitterApp(Context context, String consumerKey, String secretKey) {
		this.context	= context;
		
		mTwitter = new TwitterFactory().getInstance();
		mSession		= new TwitterSession(context);
		mProgressDlg	= new ProgressDialog(context);
		mProgressDlg.setCancelable(false);
		mProgressDlg.requestWindowFeature(Window.FEATURE_NO_TITLE);
		
		//create callback_url add start
		Resources m_r = context.getResources();
		CALLBACK_URL = String.format(CALLBACK_URL_FORMAT, 
				m_r.getString(R.string.callback_scheme), 
				m_r.getString(R.string.callback_host));
		//create callback_url add end
		mConsumerKey 	= consumerKey;
		mSecretKey	 	= secretKey;
	
		mHttpOauthConsumer = new CommonsHttpOAuthConsumer(mConsumerKey, mSecretKey);
		mHttpOauthprovider = new DefaultOAuthProvider("https://twitter.com/oauth/request_token",
													 "https://twitter.com/oauth/access_token",
													 "https://twitter.com/oauth/authorize");
		
		mAccessToken	= mSession.getAccessToken();
		
		configureToken();
	}
	
	public void setListener(TwDialogListener listener) {
		mListener = listener;
	}
	
	private void configureToken() {
		if (mAccessToken != null) {
			if (mInit) {
				mTwitter.setOAuthConsumer(mConsumerKey, mSecretKey);
				mInit = false;
			}
			mTwitter.setOAuthAccessToken(mAccessToken);
		}
	}
	
	public boolean hasAccessToken() {
		return (mAccessToken == null) ? false : true;
	}
	
	public void resetAccessToken() {
		if (mAccessToken != null) {
			mSession.resetAccessToken();
			mAccessToken = null;
		}
	}
	
	public String getUsername() {
		return mSession.getUsername();
	}
	
	public void updateStatus(String status) throws Exception {
		try {
			mTwitter.updateStatus(status);
		} catch (TwitterException e) {
			throw e;
		}
	}
	
	public void updateStatus(String status, String imagePath)  throws Exception {
		StatusUpdate update = new StatusUpdate(status);	
		update.setMedia(new File(imagePath));
		try {	
			mTwitter.updateStatus(update);
		} catch (TwitterException e) {
			throw e;
		}
	}
	

	//support twitpic add start
	public String updateStatusTwitPic(String status, String imagePath,String twitPicKey)  throws Exception {
        ConfigurationBuilder cb2 = new ConfigurationBuilder()
        .setOAuthConsumerKey(mTwitter.getConfiguration().getOAuthConsumerKey())
        .setOAuthConsumerSecret(mTwitter.getConfiguration().getOAuthConsumerSecret())
        .setOAuthAccessToken(mTwitter.getOAuthAccessToken().getToken())
        .setOAuthAccessTokenSecret(mTwitter.getOAuthAccessToken().getTokenSecret());
        
        MediaProvider mediaprovider = MediaProvider.TWITPIC;
        if(mediaprovider==MediaProvider.TWITPIC){
            cb2.setMediaProviderAPIKey(twitPicKey);
        }
		twitter4j.conf.Configuration conf = cb2.build();  
		
		File newfile = new File(imagePath);
		twitter4j.media.ImageUpload upload1 = new ImageUploadFactory(conf).getInstance(mediaprovider);
	  	return upload1.upload(newfile,status); 
	}
	//support twitpic add end

	
	public void authorize() {
		mProgressDlg.setMessage("Initializing ...");
		mProgressDlg.show();
		
		new Thread() {
			@Override
			public void run() {
				String authUrl = "";
				int what = 1;
				try {
					authUrl = mHttpOauthprovider.retrieveRequestToken(mHttpOauthConsumer, CALLBACK_URL);						
					what = 0;					
					LogD("Request token url " + authUrl);
				} catch (Exception e) {
					LogD("Failed to get request token");					
					e.printStackTrace();
				}				
				mHandler.sendMessage(mHandler.obtainMessage(what, 1, 0, authUrl));
			}
		}.start();
	}
	
	public void processToken(String callbackUrl)  {
		mProgressDlg.setMessage("Finalizing ...");
		mProgressDlg.show();
		
		final String verifier = getVerifier(callbackUrl);

		new Thread() {
			@Override
			public void run() {
				int what = 1;				
				try {
					mHttpOauthprovider.retrieveAccessToken(mHttpOauthConsumer, verifier);		
					mAccessToken = new AccessToken(mHttpOauthConsumer.getToken(), mHttpOauthConsumer.getTokenSecret());				
					configureToken();				
					User user = mTwitter.verifyCredentials();				
			        mSession.storeAccessToken(mAccessToken, user.getName());			        
			        what = 0;
				} catch (Exception e){
					LogD("Error getting access token");					
					e.printStackTrace();
				}				
				mHandler.sendMessage(mHandler.obtainMessage(what, 2, 0));
			}
		}.start();
	}
	
	private String getVerifier(String callbackUrl) {
		String verifier	 = "";		
		try {
			callbackUrl = callbackUrl.replace("twitterapp", "http");			
			URL url 		= new URL(callbackUrl);
			String query 	= url.getQuery();		
			String array[]	= query.split("&");
			for (String parameter : array) {
	             String v[] = parameter.split("=");	             
	             if (URLDecoder.decode(v[0]).equals(oauth.signpost.OAuth.OAUTH_VERIFIER)) {
	            	 verifier = URLDecoder.decode(v[1]);
	            	 break;
	             }
	        }
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}		
		return verifier;
	}
	
	private void showLoginDialog(String url) {
		final TwDialogListener listener = new TwDialogListener() {
			@Override
			public void onComplete(String value) {
				processToken(value);
			}
			
			@Override
			public void onError(int flag, String value) {
				mListener.onError(Consts.EFAILED_OPENING_AUTHORIZATION_PAGE, "Failed opening authorization page");
			}
		};
		
		new TwitterDialog(context, url, listener).show();
	}
	
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			mProgressDlg.dismiss();
			
			if (msg.what == 1) {
				if (msg.arg1 == 1)
					mListener.onError(Consts.EGETTING_REQUEST_TOKEN, "Error getting request token");
				else
					mListener.onError(Consts.EGETTING_ACCESS_TOKEN, "Error getting access token");
			}else {
				if (msg.arg1 == 1)
					showLoginDialog((String) msg.obj);
				else
					mListener.onComplete("");
			}
		}
	};
	
	public interface TwDialogListener {
		public void onComplete(String value);		
		
		public void onError(int flag, String value);
	}
	
}

*1:まあeclipseなんか一生使わないよ!な人は遣らなくてもいいかもですが・・<汗

*2:でもこれ apply plugin: 'android-library' の時のみ動いてるっぽいんだよな。。<汗

*3:まあここらへんは320*50等指定していてもそれより大きい広告を表示される場合があり=>みっともない から来るわけだが。。。<汗