cocos2d-x-3.0beta2のプロジェクトをgradle化してみる(x-plugin検証<AdMob,twitter plugin編)
自メモ)
記事分割
分割元:
- cocos2d-x-3.0beta2メモ - exception think
- cocos2d-x-3.0beta2のプロジェクトをgradle化してみる(比較検証版) - exception think
- cocos2d-x-3.0beta2のプロジェクトをgradle化してみる(x-plugin検証<インターフェース編) - exception think
さて実際のx-pluginを使ってみる。
一応中華依存サービスではなく、Androidで普通に使えそうなのは
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して、実機転送すると落ちる
理由は
- admob/proj.android/
AndroidManifest.xml
ForManifest.xml
bin
build.xml
gen
libs //<= なんも入ってない
local.properties
project.properties
res
sdk //<= GoogleAdMobAdsSdk.jar
src
- build.xmlの一番末尾
<!-- 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
- admob
irof
├── Classes
├── cocos2d
├──plugin
├──protocols/proj.android
├──plugins
├──admob/proj.android
├──twitter/proj.android
//サイズ指定版の追加 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); }
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- //adMob --> <string name="adUnitId"></string> </resources>
最新のAdmobに差し替え
GoogleAdMobAdsSdk-6.4.1.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.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!"); } }
- twitter plugin
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); } }