diff --git a/plugin/plugins/twitter/include/SocialTwitter.h b/plugin/plugins/twitter/include/SocialTwitter.h new file mode 100755 index 0000000000..7b99bd54c0 --- /dev/null +++ b/plugin/plugins/twitter/include/SocialTwitter.h @@ -0,0 +1,58 @@ +#ifndef __CCX_SOCIAL_TWITTER_H__ +#define __CCX_SOCIAL_TWITTER_H__ + +#include "ProtocolSocial.h" +#include +#include + +namespace cocos2d { namespace plugin { + +class SocialTwitter : public ProtocolSocial +{ + PLUGIN_REGISTER_DECL(SocialTwitter) +public: + /** + @brief plugin initialization + */ + virtual bool init(); + + /** + @brief initialize the developer info + @param devInfo This parameter is the info of developer, must contains key: + AlipayPartner The partner id of alipay account + AlipaySeller The seller id of alipay account + AlipayRsaPrivate The RSA private key of alipay account + AlipayPublic The public key of alipay account + AlipayNotifyUrl The notify url of developer (must not be empty) + AlipayPluginName The apk file name of Alipay (must not be empty) + @warning Must invoke this interface before other interfaces. + And invoked only once. + */ + virtual void initDeveloperInfo(TDeveloperInfo devInfo); + + /** + @brief pay for product + @param info The info of product, must contains key: + productName The name of product + productPrice The price of product(must can be parse to float) + productDesc The description of product + @warning For different plugin, the parameter should have other keys to pay. + Look at the manual of plugins. + */ + virtual void share(TShareInfo info); + + /** + @brief Set whether needs to output logs to console. + @param debug if true debug mode enabled, or debug mode disabled. + */ + virtual void setDebugMode(bool debug); + + virtual const char* getPluginVersion() { return "v0.1.01"; }; + virtual const char* getSDKVersion(); + + virtual ~SocialTwitter(); +}; + +}} // namespace cocos2d { namespace plugin { + +#endif /* __CCX_SOCIAL_TWITTER_H__ */ diff --git a/plugin/plugins/twitter/platform/android/SocialTwitter.cpp b/plugin/plugins/twitter/platform/android/SocialTwitter.cpp new file mode 100755 index 0000000000..4b26c8f6d8 --- /dev/null +++ b/plugin/plugins/twitter/platform/android/SocialTwitter.cpp @@ -0,0 +1,55 @@ +#include "SocialTwitter.h" +#include "PluginUtils.h" + +namespace cocos2d { namespace plugin { + +PLUGIN_REGISTER_IMPL(SocialTwitter) + +SocialTwitter::~SocialTwitter() +{ +} + +/** +@brief plugin initialization +*/ +bool SocialTwitter::init() +{ + return PluginUtils::initJavaPlugin(this, "org.cocos2dx.plugin.SocialTwitter"); +} + +/** +@brief initialize the developer info +@param devInfo This parameter is the info of developer, must contains key: + consumerkey The consumerkey of twitter account + consumersecret The consumersecret of twitter account + More: https://dev.twitter.com +@warning Must invoke this interface before other interfaces. + And invoked only once. +*/ +void SocialTwitter::initDeveloperInfo(TDeveloperInfo devInfo) +{ + ProtocolSocial::initDeveloperInfo(devInfo); +} + +/** +@brief pay for product +@param info The info of product, must contains key: + text The text to share + imagePath The full path of image to share +*/ +void SocialTwitter::share(TShareInfo info) +{ + ProtocolSocial::share(info); +} + +const char* SocialTwitter::getSDKVersion() +{ + return ProtocolSocial::getSDKVersion(); +} + +void SocialTwitter::setDebugMode(bool debug) +{ + ProtocolSocial::setDebugMode(debug); +} + +}} // namespace cocos2d { namespace plugin { diff --git a/plugin/plugins/twitter/proj.android/.classpath b/plugin/plugins/twitter/proj.android/.classpath new file mode 100755 index 0000000000..4ba22f534d --- /dev/null +++ b/plugin/plugins/twitter/proj.android/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/plugin/plugins/twitter/proj.android/.project b/plugin/plugins/twitter/proj.android/.project new file mode 100755 index 0000000000..9aade58531 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/.project @@ -0,0 +1,45 @@ + + + libPluginTwitter + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + + + android + 2 + PARENT-1-PROJECT_LOC/platform/android + + + include + 2 + PARENT-1-PROJECT_LOC/include + + + diff --git a/plugin/plugins/twitter/proj.android/AndroidManifest.xml b/plugin/plugins/twitter/proj.android/AndroidManifest.xml new file mode 100755 index 0000000000..8582917b67 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/plugin/plugins/twitter/proj.android/ForAssets/alipay_plugin.apk.REMOVED.git-id b/plugin/plugins/twitter/proj.android/ForAssets/alipay_plugin.apk.REMOVED.git-id new file mode 100644 index 0000000000..e7115f0d77 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/ForAssets/alipay_plugin.apk.REMOVED.git-id @@ -0,0 +1 @@ +db46ceaf2554c8d9e48cdaec3a4cdf5519bb8896 \ No newline at end of file diff --git a/plugin/plugins/twitter/proj.android/ForManifest.xml b/plugin/plugins/twitter/proj.android/ForManifest.xml new file mode 100755 index 0000000000..00d34cd419 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/ForManifest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugin/plugins/twitter/proj.android/build.xml b/plugin/plugins/twitter/proj.android/build.xml new file mode 100755 index 0000000000..10e9663ff5 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/build.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/plugins/twitter/proj.android/build_native.sh b/plugin/plugins/twitter/proj.android/build_native.sh new file mode 100755 index 0000000000..0b272b9465 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/build_native.sh @@ -0,0 +1,20 @@ +# set params +PLUGIN_ANDROID_ROOT=$(cd "$(dirname "$0")"; pwd) + +if [ ! "${PLUGIN_ROOT}" ]; then + PLUGIN_ROOT="$PLUGIN_ANDROID_ROOT"/../.. +fi + +# build +"$ANDROID_NDK_ROOT"/ndk-build -C "$PLUGIN_ANDROID_ROOT" \ +NDK_MODULE_PATH="$PLUGIN_ROOT" + +echo +if [ "0" != "$?" ]; then + echo "Build error occoured!!!" + exit 1 +fi + +echo +echo "Native build action success." +exit 0 \ No newline at end of file diff --git a/plugin/plugins/twitter/proj.android/jni/Android.mk b/plugin/plugins/twitter/proj.android/jni/Android.mk new file mode 100755 index 0000000000..e4c920eb4c --- /dev/null +++ b/plugin/plugins/twitter/proj.android/jni/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := PluginTwitterStatic + +LOCAL_MODULE_FILENAME := libPluginTwitterStatic + +LOCAL_SRC_FILES := \ +$(addprefix ../../platform/android/, \ + SocialTwitter.cpp \ +) \ + +LOCAL_CFLAGS := + +LOCAL_EXPORT_CFLAGS := + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../include + +LOCAL_WHOLE_STATIC_LIBRARIES := PluginProtocolStatic + +LOCAL_LDLIBS := -landroid +LOCAL_LDLIBS += -llog + +include $(BUILD_STATIC_LIBRARY) + +$(call import-module, protocols/proj.android/jni) diff --git a/plugin/plugins/twitter/proj.android/jni/Application.mk b/plugin/plugins/twitter/proj.android/jni/Application.mk new file mode 100755 index 0000000000..e4935028c3 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/jni/Application.mk @@ -0,0 +1,7 @@ +# it is needed for ndk-r5 +APP_STL := gnustl_static +APP_CPPFLAGS += -frtti +APP_MODULES := PluginTwitterStatic +APP_ABI :=armeabi +#APP_ABI :=x86 +#APP_ABI :=mips mips-r2 mips-r2-sf armeabi diff --git a/plugin/plugins/twitter/proj.android/project.properties b/plugin/plugins/twitter/proj.android/project.properties new file mode 100755 index 0000000000..9d741eed16 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/project.properties @@ -0,0 +1,16 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-7 +android.library=true +android.library.reference.1=../../../protocols/proj.android diff --git a/plugin/plugins/twitter/proj.android/res/.gitignore b/plugin/plugins/twitter/proj.android/res/.gitignore new file mode 100755 index 0000000000..e69de29bb2 diff --git a/plugin/plugins/twitter/proj.android/sdk/signpost-commonshttp4-1.2.1.1.jar b/plugin/plugins/twitter/proj.android/sdk/signpost-commonshttp4-1.2.1.1.jar new file mode 100755 index 0000000000..50e9838e6f Binary files /dev/null and b/plugin/plugins/twitter/proj.android/sdk/signpost-commonshttp4-1.2.1.1.jar differ diff --git a/plugin/plugins/twitter/proj.android/sdk/signpost-core-1.2.1.1.jar b/plugin/plugins/twitter/proj.android/sdk/signpost-core-1.2.1.1.jar new file mode 100755 index 0000000000..59e7537f51 Binary files /dev/null and b/plugin/plugins/twitter/proj.android/sdk/signpost-core-1.2.1.1.jar differ diff --git a/plugin/plugins/twitter/proj.android/sdk/signpost-jetty6-1.2.1.1.jar b/plugin/plugins/twitter/proj.android/sdk/signpost-jetty6-1.2.1.1.jar new file mode 100755 index 0000000000..b5d974c7ce Binary files /dev/null and b/plugin/plugins/twitter/proj.android/sdk/signpost-jetty6-1.2.1.1.jar differ diff --git a/plugin/plugins/twitter/proj.android/sdk/twitter4j-core-android-3.0.1.jar.REMOVED.git-id b/plugin/plugins/twitter/proj.android/sdk/twitter4j-core-android-3.0.1.jar.REMOVED.git-id new file mode 100644 index 0000000000..cd6a606604 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/sdk/twitter4j-core-android-3.0.1.jar.REMOVED.git-id @@ -0,0 +1 @@ +62d02b6f0d450b3b64d061280594018742ddcd27 \ No newline at end of file diff --git a/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/Consts.java b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/Consts.java new file mode 100644 index 0000000000..74b4ea8da2 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/Consts.java @@ -0,0 +1,9 @@ +package org.cocos2dx.plugin; + +public interface Consts { + public static int EGETTING_ACCESS_TOKEN =0; + public static int EUSER_CANCELED = 1; + public static int EGETTING_REQUEST_TOKEN=2; + public static int EFAILED_OPENING_AUTHORIZATION_PAGE=3; + public static int EPAGE_ERROR =4; +} diff --git a/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/SocialTwitter.java b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/SocialTwitter.java new file mode 100755 index 0000000000..8a701a6fd0 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/SocialTwitter.java @@ -0,0 +1,172 @@ +package org.cocos2dx.plugin; + +import java.util.Hashtable; + +import org.cocos2dx.plugin.InterfaceSocial.ShareAdapter; +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; + +public class SocialTwitter implements ShareAdapter { + + private static final String LOG_TAG = "SocialTwitter"; + private static Activity mContext = null; + protected static boolean bDebug = false; + private static String CONSUMER_KEY=""; + private static String CONSUMER_SECRET=""; + + private static TwitterApp mTwitter = null; + private static boolean isInitialized = false; + private static Hashtable mShareInfo = null; + + public static String KEY_TEXT="text"; + public static String KEY_IMAGE_PATH = "imagePath"; + + 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 SocialTwitter(Context context) { + mContext = (Activity) context; + } + + + @Override + public void initDeveloperInfo(Hashtable cpInfo) { + LogD("initDeveloperInfo invoked " + cpInfo.toString()); + mShareInfo = cpInfo; + mShareInfo = cpInfo; + try { + SocialTwitter.CONSUMER_KEY = cpInfo.get("consumerkey"); + SocialTwitter.CONSUMER_SECRET = cpInfo.get("consumersecret"); + if(isInitialized){ + return; + } + isInitialized = true; + PluginWrapper.runOnMainThread(new Runnable() { + + @Override + public void run() { + mTwitter = new TwitterApp(PluginWrapper.getContext(), SocialTwitter.CONSUMER_KEY, SocialTwitter.CONSUMER_SECRET); + mTwitter.setListener(mTwLoginDialogListener); + } + }); + } catch (Exception e) { + LogE("Developer info is wrong!", e); + } + + } + + @Override + public void share(Hashtable info) { + LogD("share invoked " + info.toString()); + mShareInfo = info; + if (! networkReachable()) { + shareResult(InterfaceSocial.SHARERESULT_FAIL, "网络不可用"); + 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() { + String text = mShareInfo.get(KEY_TEXT); + String imagePath = mShareInfo.get(KEY_IMAGE_PATH); + try { + if(imagePath != null && imagePath.length() > 0){ + mTwitter.updateStatus(text, imagePath); + }else{ + mTwitter.updateStatus(text); + } + LogD("Posted to Twitter!"); + shareResult(InterfaceSocial.SHARERESULT_SUCCESS, "user lihex"); + } catch (Exception e) { + LogD("Post to Twitter failed!"); + shareResult(InterfaceSocial.SHARERESULT_FAIL, "user lihex"); + e.printStackTrace(); + } + } + }); + } + + @Override + public void setDebugMode(boolean debug) { + bDebug = debug; + } + + @Override + public String getSDKVersion() { + return "Unknown version"; + } + + 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) { + InterfaceSocial.shareResult(ret, msg); + LogD("SocialTwitter result : " + ret + " msg : " + msg); + } + + private static final TwDialogListener mTwLoginDialogListener = new TwDialogListener() { + + @Override + public void onError(int flag, String value) { + LogD("Twitter connection failed!"); + shareResult(InterfaceSocial.SHARERESULT_FAIL, value); + } + + @Override + public void onComplete(String value) { + String username = mTwitter.getUsername(); + LogD("Connected to Twitter as" + username); + String text = mShareInfo.get(KEY_TEXT); + String imagePath = mShareInfo.get(KEY_IMAGE_PATH); + try { + if(imagePath != null && imagePath.length() > 0){ + mTwitter.updateStatus(text, imagePath); + }else{ + mTwitter.updateStatus(text); + } + LogD("Posted to Twitter!"); + shareResult(InterfaceSocial.SHARERESULT_SUCCESS, username); + } catch (Exception e) { + LogD("Post to Twitter failed!"); + shareResult(InterfaceSocial.SHARERESULT_FAIL, username); + e.printStackTrace(); + } + } + }; +} diff --git a/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterApp.java b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterApp.java new file mode 100755 index 0000000000..61662c6b8b --- /dev/null +++ b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterApp.java @@ -0,0 +1,237 @@ +/** + * @author Lorensius W. L. T + * + * 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 android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.Window; + +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"; + public static final String CALLBACK_URL = "twitterapp://connect"; + + protected static void LogE(String msg, Exception e) { + Log.e(LOG_TAG, msg, e); + e.printStackTrace(); + } + + protected static void LogD(String msg) { + if (SocialTwitter.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); + + 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; + } + } + + 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); + } + +} \ No newline at end of file diff --git a/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterDialog.java b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterDialog.java new file mode 100755 index 0000000000..68303860a6 --- /dev/null +++ b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterDialog.java @@ -0,0 +1,182 @@ +/** + * Modified from FbDialog from Facebook SDK + * + * Lorensius W. L. T + */ +package org.cocos2dx.plugin; + +import org.cocos2dx.plugin.TwitterApp.TwDialogListener; + +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Bundle; +import android.util.Log; +import android.view.Display; +import android.view.ViewGroup; +import android.view.Window; +import android.webkit.CookieManager; +import android.webkit.CookieSyncManager; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class TwitterDialog extends Dialog { + static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT); + static final int MARGIN = 4; + static final int PADDING = 2; + + private String mUrl; + private TwDialogListener mListener; + private ProgressDialog mSpinner; + private WebView mWebView; + private LinearLayout mContent; + private TextView mTitle; + + private static final String LOG_TAG = "Twitter-WebView"; + + protected static void LogD(String msg) { + if (SocialTwitter.bDebug) { + Log.d(LOG_TAG, msg); + } + } + public TwitterDialog(Context context, String url, TwDialogListener listener) { + super(context); + + mUrl = url; + mListener = listener; + setOnCancelListener(mCancelListener); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mSpinner = new ProgressDialog(getContext()); + + mSpinner.requestWindowFeature(Window.FEATURE_NO_TITLE); + mSpinner.setMessage("Loading..."); + mSpinner.setCancelable(false); + + mContent = new LinearLayout(getContext()); + + mContent.setOrientation(LinearLayout.VERTICAL); + + setUpTitle(); + setUpWebView(); + + Display display = getWindow().getWindowManager().getDefaultDisplay(); + double[] dimensions = new double[2]; + + if (display.getWidth() < display.getHeight()) { + dimensions[0] = 0.87 * display.getWidth(); + dimensions[1] = 0.82 * display.getHeight(); + } else { + dimensions[0] = 0.75 * display.getWidth(); + dimensions[1] = 0.75 * display.getHeight(); + } + + addContentView(mContent, new FrameLayout.LayoutParams((int) dimensions[0], (int) dimensions[1])); + } + + private void setUpTitle() { + requestWindowFeature(Window.FEATURE_NO_TITLE); + + // Drawable icon = getContext().getResources().getDrawable(R.drawable.twitter_icon); + + mTitle = new TextView(getContext()); + + mTitle.setText("Twitter"); + mTitle.setTextColor(Color.WHITE); + mTitle.setTypeface(Typeface.DEFAULT_BOLD); + mTitle.setBackgroundColor(0xFFbbd7e9); + mTitle.setPadding(MARGIN + PADDING, MARGIN, MARGIN, MARGIN); + mTitle.setCompoundDrawablePadding(MARGIN + PADDING); + // mTitle.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); + mTitle.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); + + mContent.addView(mTitle); + } + + private void setUpWebView() { + CookieSyncManager.createInstance(getContext()); + CookieManager cookieManager = CookieManager.getInstance(); + cookieManager.removeAllCookie(); + + mWebView = new WebView(getContext()); + + mWebView.setVerticalScrollBarEnabled(false); + mWebView.setHorizontalScrollBarEnabled(false); + mWebView.setWebViewClient(new TwitterWebViewClient()); + mWebView.getSettings().setJavaScriptEnabled(true); + mWebView.loadUrl(mUrl); + mWebView.setLayoutParams(FILL); + + + mContent.addView(mWebView); + } + + private class TwitterWebViewClient extends WebViewClient { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + LogD("Redirecting URL " + url); + + if (url.startsWith(TwitterApp.CALLBACK_URL)) { + mListener.onComplete(url); + + TwitterDialog.this.dismiss(); + + return true; + } else if (url.startsWith("authorize")) { + return false; + } + + return true; + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + LogD("Page error: " + description); + + super.onReceivedError(view, errorCode, description, failingUrl); + + mListener.onError(Consts.EPAGE_ERROR, description); + + TwitterDialog.this.dismiss(); + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + LogD("Loading URL: " + url); + super.onPageStarted(view, url, favicon); + mSpinner.show(); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + String title = mWebView.getTitle(); + if (title != null && title.length() > 0) { + mTitle.setText(title); + } + mSpinner.dismiss(); + } + } + + private DialogInterface.OnCancelListener mCancelListener = new OnCancelListener() { + + @Override + public void onCancel(DialogInterface dialog) { + mSpinner.dismiss(); + mListener.onError(Consts.EUSER_CANCELED, "User canceled!"); + } + }; +} diff --git a/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterSession.java b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterSession.java new file mode 100755 index 0000000000..adcb4fe3ea --- /dev/null +++ b/plugin/plugins/twitter/proj.android/src/org/cocos2dx/plugin/TwitterSession.java @@ -0,0 +1,56 @@ +/** + * @author Lorensius W. L. T + * + * http://www.londatiga.net + */ +package org.cocos2dx.plugin; + +import twitter4j.auth.AccessToken; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; + +public class TwitterSession { + private SharedPreferences sharedPref; + private Editor editor; + + private static final String TWEET_AUTH_KEY = "auth_key"; + private static final String TWEET_AUTH_SECRET_KEY = "auth_secret_key"; + private static final String TWEET_USER_NAME = "user_name"; + private static final String SHARED = "Twitter_Preferences"; + + public TwitterSession(Context context) { + sharedPref = context.getSharedPreferences(SHARED, Context.MODE_PRIVATE); + editor = sharedPref.edit(); + } + + public void storeAccessToken(AccessToken accessToken, String username) { + editor.putString(TWEET_AUTH_KEY, accessToken.getToken()); + editor.putString(TWEET_AUTH_SECRET_KEY, accessToken.getTokenSecret()); + editor.putString(TWEET_USER_NAME, username); + + editor.commit(); + } + + public void resetAccessToken() { + editor.putString(TWEET_AUTH_KEY, null); + editor.putString(TWEET_AUTH_SECRET_KEY, null); + editor.putString(TWEET_USER_NAME, null); + + editor.commit(); + } + + public String getUsername() { + return sharedPref.getString(TWEET_USER_NAME, ""); + } + + public AccessToken getAccessToken() { + String token = sharedPref.getString(TWEET_AUTH_KEY, null); + String tokenSecret = sharedPref.getString(TWEET_AUTH_SECRET_KEY, null); + + if (token != null && tokenSecret != null) + return new AccessToken(token, tokenSecret); + else + return null; + } +} \ No newline at end of file diff --git a/plugin/protocols/include/ProtocolSocial.h b/plugin/protocols/include/ProtocolSocial.h new file mode 100755 index 0000000000..865c9a95c0 --- /dev/null +++ b/plugin/protocols/include/ProtocolSocial.h @@ -0,0 +1,89 @@ +#ifndef __CXX_PROTOCOL_SOCIAL_H__ +#define __CXX_PROTOCOL_SOCIAL_H__ + +#include "PluginProtocol.h" +#include +#include + +namespace cocos2d { namespace plugin { + +typedef std::map TDeveloperInfo; +typedef std::map TShareInfo; + +typedef enum +{ + eShareSuccess = 0, + eShareFail, + eShareCancel, + eShareTimeOut, +} EShareResult; + +class ShareResultListener +{ +public: + virtual void shareResult(EShareResult ret, const char* msg, TShareInfo info) = 0; +}; + +class ProtocolSocial : public PluginProtocol +{ +public: + + /** + @brief plugin initialization + */ + virtual bool init(); + + /** + @brief initialize the developer info + @param devInfo This parameter is the info of developer, + different plugin have different format + @warning Must invoke this interface before other interfaces. + And invoked only once. + */ + virtual void initDeveloperInfo(TDeveloperInfo devInfo); + + /** + @brief share information + @param info The info of share, must contains key: + text The text of share + @warning For different plugin, the parameter should have other keys to share. + Look at the manual of plugins. + */ + virtual void share(TShareInfo info); + + /** + @brief Set whether needs to output logs to console. + @param debug if true debug mode enabled, or debug mode disabled. + */ + virtual void setDebugMode(bool debug); + + /** + @breif set the result listener + @param pListener The callback object for share result + @wraning Must invoke this interface before share + */ + static void setResultListener(ShareResultListener* pListener); + + /** + @brief share result callback + */ + static void shareResult(EShareResult ret, const char* msg); + + virtual const char* getPluginVersion() { return "ProtocolSocial, v0.1.00 , subclass should override this interface!"; }; + virtual const char* getSDKVersion(); + virtual const char* getPluginName() = 0; + +protected: + ProtocolSocial(); +public: + virtual ~ProtocolSocial(); + +protected: + static bool m_bSharing; + static ShareResultListener* m_pListener; + static TShareInfo m_curInfo; +}; + +}} // namespace cocos2d { namespace plugin { + +#endif /* ----- #ifndef __CXX_PROTOCOL_SOCIAL_H__ ----- */ diff --git a/plugin/protocols/platform/android/ProtocolSocial.cpp b/plugin/protocols/platform/android/ProtocolSocial.cpp new file mode 100755 index 0000000000..9825bdd722 --- /dev/null +++ b/plugin/protocols/platform/android/ProtocolSocial.cpp @@ -0,0 +1,151 @@ +#include "ProtocolSocial.h" +#include "PluginJniHelper.h" +#include +#include "PluginUtils.h" +#include "PluginJavaData.h" + +#if 1 +#define LOG_TAG "ProtocolSocial" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) +#else +#define LOGD(...) +#endif + +namespace cocos2d { namespace plugin { + +extern "C" { + JNIEXPORT void JNICALL Java_org_cocos2dx_plugin_InterfaceSocial_nativeShareResult(JNIEnv* env, jobject thiz, jint ret, jstring msg) + { + std::string strMsg = PluginJniHelper::jstring2string(msg); + ProtocolSocial::shareResult((EShareResult) ret, strMsg.c_str()); + } +} + +bool ProtocolSocial::m_bSharing = false; +ShareResultListener* ProtocolSocial::m_pListener = NULL; +TShareInfo ProtocolSocial::m_curInfo; + +ProtocolSocial::ProtocolSocial() +{ +} + +ProtocolSocial::~ProtocolSocial() +{ + PluginUtils::erasePluginJavaData(this); +} + +bool ProtocolSocial::init() +{ + return true; +} + +void ProtocolSocial::initDeveloperInfo(TDeveloperInfo devInfo) +{ + if (devInfo.empty()) + { + LOGD("The developer info is empty!"); + return; + } + else + { + PluginJavaData* pData = PluginUtils::getPluginJavaData(this); + PluginJniMethodInfo t; + if (PluginJniHelper::getMethodInfo(t + , pData->jclassName.c_str() + , "initDeveloperInfo" + , "(Ljava/util/Hashtable;)V")) + { + // generate the hashtable from map + jobject obj_Map = PluginUtils::createJavaMapObject(t, &devInfo); + + // invoke java method + t.env->CallVoidMethod(pData->jobj, t.methodID, obj_Map); + t.env->DeleteLocalRef(obj_Map); + t.env->DeleteLocalRef(t.classID); + } + } +} + +void ProtocolSocial::share(TShareInfo info) +{ + if (m_bSharing) + { + LOGD("Now is sharing"); + return; + } + + if (info.empty()) + { + if (NULL != m_pListener) + { + shareResult(eShareFail, "Share info error"); + } + LOGD("The Share info is empty!"); + return; + } + else + { + m_bSharing = true; + m_curInfo = info; + + PluginJavaData* pData = PluginUtils::getPluginJavaData(this); + PluginJniMethodInfo t; + if (PluginJniHelper::getMethodInfo(t + , pData->jclassName.c_str() + , "share" + , "(Ljava/util/Hashtable;)V")) + { + // generate the hashtable from map + jobject obj_Map = PluginUtils::createJavaMapObject(t, &info); + + // invoke java method + t.env->CallVoidMethod(pData->jobj, t.methodID, obj_Map); + t.env->DeleteLocalRef(obj_Map); + t.env->DeleteLocalRef(t.classID); + } + } +} + +void ProtocolSocial::setResultListener(ShareResultListener* pListener) +{ + m_pListener = pListener; +} + +void ProtocolSocial::shareResult(EShareResult ret, const char* msg) +{ + m_bSharing = false; + if (m_pListener) + { + m_pListener->shareResult(ret, msg, m_curInfo); + } + else + { + LOGD("Result listener is null!"); + } + m_curInfo.clear(); + LOGD("Share result is : %d(%s)", (int) ret, msg); +} + +const char* ProtocolSocial::getSDKVersion() +{ + std::string verName; + + PluginJavaData* pData = PluginUtils::getPluginJavaData(this); + PluginJniMethodInfo t; + if (PluginJniHelper::getMethodInfo(t + , pData->jclassName.c_str() + , "getSDKVersion" + , "()Ljava/lang/String;")) + { + jstring ret = (jstring)(t.env->CallObjectMethod(pData->jobj, t.methodID)); + verName = PluginJniHelper::jstring2string(ret); + } + return verName.c_str(); +} + +void ProtocolSocial::setDebugMode(bool debug) +{ + PluginUtils::callJavaFunctionWithName_oneBaseType(this, "setDebugMode", "(Z)V", debug); +} + +}} // namespace cocos2d { namespace plugin { diff --git a/plugin/protocols/proj.android/jni/Android.mk b/plugin/protocols/proj.android/jni/Android.mk old mode 100644 new mode 100755 index 9e0ad021e8..5e82597a05 --- a/plugin/protocols/proj.android/jni/Android.mk +++ b/plugin/protocols/proj.android/jni/Android.mk @@ -13,6 +13,7 @@ $(addprefix ../../platform/android/, \ ProtocolAnalytics.cpp \ ProtocolIAP.cpp \ ProtocolAds.cpp \ + ProtocolSocial.cpp \ ) \ ../../PluginManager.cpp \ ../../RegisterPlugin.cpp \ diff --git a/plugin/protocols/proj.android/src/org/cocos2dx/plugin/InterfaceSocial.java b/plugin/protocols/proj.android/src/org/cocos2dx/plugin/InterfaceSocial.java new file mode 100755 index 0000000000..a4b3cb08f6 --- /dev/null +++ b/plugin/protocols/proj.android/src/org/cocos2dx/plugin/InterfaceSocial.java @@ -0,0 +1,29 @@ +package org.cocos2dx.plugin; + +import java.util.Hashtable; + +public class InterfaceSocial { + public static final int SHARERESULT_SUCCESS = 0; + public static final int SHARERESULT_FAIL = 1; + public static final int SHARERESULT_CANCEL = 2; + public static final int SHARERESULT_TIMEOUT = 3; + + public interface ShareAdapter { + public void initDeveloperInfo(Hashtable cpInfo); + public void share(Hashtable cpInfo); + public void setDebugMode(boolean debug); + public String getSDKVersion(); + } + + public static void shareResult(int ret, String msg) { + final int curRet = ret; + final String curMsg = msg; + PluginWrapper.runOnGLThread(new Runnable() { + @Override + public void run() { + nativeShareResult(curRet, curMsg); + } + }); + } + private static native void nativeShareResult(int ret, String msg); +} diff --git a/plugin/samples/HelloSocial/Classes/AppDelegate.cpp b/plugin/samples/HelloSocial/Classes/AppDelegate.cpp new file mode 100755 index 0000000000..1efcdf0b4c --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/AppDelegate.cpp @@ -0,0 +1,60 @@ +#include "AppDelegate.h" +#include "cocos2d.h" +#include "HelloWorldScene.h" +#include "PluginManager.h" +#include "MyShareManager.h" + +using namespace cocos2d::plugin; +USING_NS_CC; + +AppDelegate::AppDelegate() +{ + +} + +AppDelegate::~AppDelegate() +{ + +} + +bool AppDelegate::applicationDidFinishLaunching() +{ + MyShareManager::sharedManager()->loadSocialPlugin(); + + // initialize director + CCDirector *pDirector = CCDirector::sharedDirector(); + pDirector->setOpenGLView(CCEGLView::sharedOpenGLView()); + CCEGLView* pEGLView = CCEGLView::sharedOpenGLView(); + pEGLView->setDesignResolutionSize(960.0f, 640.0f, kResolutionNoBorder); + // turn on display FPS + pDirector->setDisplayStats(true); + + // set FPS. the default value is 1.0/60 if you don't call this + pDirector->setAnimationInterval(1.0 / 60); + + // create a scene. it's an autorelease object + CCScene *pScene = HelloWorld::scene(); + + // run + pDirector->runWithScene(pScene); + + return true; +} + +// This function will be called when the app is inactive. When comes a phone call,it's be invoked too +void AppDelegate::applicationDidEnterBackground() +{ + CCDirector::sharedDirector()->pause(); + + // if you use SimpleAudioEngine, it must be pause + // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); +} + +// this function will be called when the app is active again +void AppDelegate::applicationWillEnterForeground() +{ + CCDirector::sharedDirector()->resume(); + + // if you use SimpleAudioEngine, it must resume here + // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); +} diff --git a/plugin/samples/HelloSocial/Classes/AppDelegate.h b/plugin/samples/HelloSocial/Classes/AppDelegate.h new file mode 100755 index 0000000000..d036940402 --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/AppDelegate.h @@ -0,0 +1,40 @@ +#ifndef _APP_DELEGATE_H_ +#define _APP_DELEGATE_H_ + +#include "CCApplication.h" + +/** +@brief The cocos2d Application. + +The reason for implement as private inheritance is to hide some interface call by CCDirector. +*/ +class AppDelegate : private cocos2d::CCApplication +{ +public: + AppDelegate(); + virtual ~AppDelegate(); + + /** + @brief Implement CCDirector and CCScene init code here. + @return true Initialize success, app continue. + @return false Initialize failed, app terminate. + */ + virtual bool applicationDidFinishLaunching(); + + /** + @brief The function be called when the application enter background + @param the pointer of the application + */ + virtual void applicationDidEnterBackground(); + + /** + @brief The function be called when the application enter foreground + @param the pointer of the application + */ + virtual void applicationWillEnterForeground(); + + static void loadAnalyticsPlugin(); +}; + +#endif // _APP_DELEGATE_H_ + diff --git a/plugin/samples/HelloSocial/Classes/HelloWorldScene.cpp b/plugin/samples/HelloSocial/Classes/HelloWorldScene.cpp new file mode 100755 index 0000000000..75535b2d64 --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/HelloWorldScene.cpp @@ -0,0 +1,126 @@ +#include "HelloWorldScene.h" +#include "PluginManager.h" +#include "AppDelegate.h" +#include "MyShareManager.h" + +using namespace cocos2d; +using namespace cocos2d::plugin; + +enum { + TAG_PAY_BY_ALIPAY = 100, + TAG_PAY_BY_ND91, +}; + +typedef struct tagEventMenuItem { + std::string id; + int tag; +}EventMenuItem; + +static EventMenuItem s_EventMenuItem[] = { + {"twitter.jpeg", TAG_PAY_BY_ALIPAY} +}; + +CCScene* HelloWorld::scene() +{ + // 'scene' is an autorelease object + CCScene *scene = CCScene::create(); + + // 'layer' is an autorelease object + HelloWorld *layer = HelloWorld::create(); + + // add layer as a child to scene + scene->addChild(layer); + + // return the scene + return scene; +} + +// on "init" you need to initialize your instance +bool HelloWorld::init() +{ + ////////////////////////////// + // 1. super init first + if ( !CCLayer::init() ) + { + return false; + } + + CCSize size = CCDirector::sharedDirector()->getVisibleSize(); + + CCSprite* pBackground = CCSprite::create("background.png"); + pBackground->setPosition(ccp(size.width / 2, size.height / 2)); + addChild(pBackground); + ///////////////////////////// + // 2. add a menu item with "X" image, which is clicked to quit the program + // you may modify it. + + CCEGLView* pEGLView = CCEGLView::sharedOpenGLView(); + CCPoint posBR = ccp(pEGLView->getVisibleOrigin().x + pEGLView->getVisibleSize().width, pEGLView->getVisibleOrigin().y); + CCPoint posBC = ccp(pEGLView->getVisibleOrigin().x + pEGLView->getVisibleSize().width/2, pEGLView->getVisibleOrigin().y); + CCPoint posTL = ccp(pEGLView->getVisibleOrigin().x, pEGLView->getVisibleOrigin().y + pEGLView->getVisibleSize().height); + + // add a "close" icon to exit the progress. it's an autorelease object + CCMenuItemImage *pCloseItem = CCMenuItemImage::create( + "CloseNormal.png", + "CloseSelected.png", + this, + menu_selector(HelloWorld::menuCloseCallback) ); + pCloseItem->setPosition( ccp(posBR.x - 20, posBR.y + 20) ); + + // create menu, it's an autorelease object + CCMenu* pMenu = CCMenu::create(pCloseItem, NULL); + pMenu->setPosition( CCPointZero ); + this->addChild(pMenu, 1); + + CCPoint posStep = ccp(220, -150); + CCPoint beginPos = ccpAdd(posTL, ccpMult(posStep, 0.5f)); + int line = 0; + int row = 0; + for (int i = 0; i < sizeof(s_EventMenuItem)/sizeof(s_EventMenuItem[0]); i++) { + CCMenuItemImage* pMenuItem = CCMenuItemImage::create(s_EventMenuItem[i].id.c_str(), s_EventMenuItem[i].id.c_str(), + this, menu_selector(HelloWorld::eventMenuCallback)); + pMenu->addChild(pMenuItem, 0, s_EventMenuItem[i].tag); + + CCPoint pos = ccpAdd(beginPos, ccp(posStep.x * row, posStep.y * line)); + CCSize itemSize = pMenuItem->getContentSize(); + if ((pos.x + itemSize.width / 2) > posBR.x) + { + line += 1; + row = 0; + pos = ccpAdd(beginPos, ccp(posStep.x * row, posStep.y * line)); + } + row += 1; + pMenuItem->setPosition(pos); + } + + CCLabelTTF* label = CCLabelTTF::create("Reload all plugins", "Arial", 24); + CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(HelloWorld::reloadPluginMenuCallback)); + pMenuItem->setAnchorPoint(ccp(0.5f, 0)); + pMenu->addChild(pMenuItem, 0); + pMenuItem->setPosition(posBC); + + return true; +} + +void HelloWorld::reloadPluginMenuCallback(CCObject* pSender) +{ + MyShareManager::sharedManager()->unloadSocialPlugin(); + MyShareManager::sharedManager()->loadSocialPlugin(); +} + +void HelloWorld::eventMenuCallback(CCObject* pSender) +{ + TShareInfo pInfo; + pInfo["text"] = "MyFirst tweet!"; + // pInfo["imagePath"] = "Full/path/to/image"; + MyShareManager::sharedManager()->shareByMode(pInfo, MyShareManager::eTwitter); +} + +void HelloWorld::menuCloseCallback(CCObject* pSender) +{ + MyShareManager::purgeManager(); + CCDirector::sharedDirector()->end(); +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) + exit(0); +#endif +} diff --git a/plugin/samples/HelloSocial/Classes/HelloWorldScene.h b/plugin/samples/HelloSocial/Classes/HelloWorldScene.h new file mode 100755 index 0000000000..cf90652eeb --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/HelloWorldScene.h @@ -0,0 +1,24 @@ +#ifndef __HELLOWORLD_SCENE_H__ +#define __HELLOWORLD_SCENE_H__ + +#include "cocos2d.h" + +class HelloWorld : public cocos2d::CCLayer +{ +public: + // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone + virtual bool init(); + + // there's no 'id' in cpp, so we recommand to return the exactly class pointer + static cocos2d::CCScene* scene(); + + // a selector callback + void menuCloseCallback(CCObject* pSender); + void eventMenuCallback(CCObject* pSender); + void reloadPluginMenuCallback(CCObject* pSender); + + // implement the "static node()" method manually + CREATE_FUNC(HelloWorld); +}; + +#endif // __HELLOWORLD_SCENE_H__ diff --git a/plugin/samples/HelloSocial/Classes/MyShareManager.cpp b/plugin/samples/HelloSocial/Classes/MyShareManager.cpp new file mode 100755 index 0000000000..9bd4add8e2 --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/MyShareManager.cpp @@ -0,0 +1,106 @@ +#include "MyShareManager.h" +#include "PluginManager.h" +#include "cocos2d.h" + +using namespace cocos2d::plugin; +using namespace cocos2d; + +MyShareManager* MyShareManager::s_pManager = NULL; + +MyShareManager::MyShareManager() +: s_pRetListener(NULL) +, s_pTwitter(NULL) +{ + +} + +MyShareManager::~MyShareManager() +{ + unloadSocialPlugin(); + if (s_pRetListener) + { + delete s_pRetListener; + } +} + +MyShareManager* MyShareManager::sharedManager() +{ + if (s_pManager == NULL) { + s_pManager = new MyShareManager(); + } + return s_pManager; +} + +void MyShareManager::purgeManager() +{ + if (s_pManager) + { + delete s_pManager; + } +} + +void MyShareManager::loadSocialPlugin() +{ + { + // init twitter plugin + s_pTwitter = dynamic_cast(PluginManager::getInstance()->loadPlugin("SocialTwitter")); + TDeveloperInfo pTwitterInfo; + + /* Warning: must set your twiiter dev info here */ + // pTwitterInfo["consumerkey"] = "your consumerkey"; + // pTwitterInfo["consumersecret"] = "your consumersecret"; + + if (pTwitterInfo.empty()) + { + char msg[256] = { 0 }; + sprintf(msg, "Developer info is empty. PLZ fill your twitter info in %s(nearby line %d)", __FILE__, __LINE__); + CCMessageBox(msg, "Twitter Warning"); + } + s_pTwitter->setDebugMode(true); + s_pTwitter->initDeveloperInfo(pTwitterInfo); + } + + if (s_pRetListener == NULL) + { + s_pRetListener = new MyShareResult(); + ProtocolSocial::setResultListener(s_pRetListener); + } +} + +void MyShareManager::unloadSocialPlugin() +{ + if (s_pTwitter) + { + PluginManager::getInstance()->unloadPlugin("SocialTwitter"); + s_pTwitter = NULL; + } +} + +void MyShareManager::shareByMode(TShareInfo info, MyShareMode mode) +{ + ProtocolSocial* pShare = NULL; + switch(mode) + { + case eTwitter: + pShare = s_pTwitter; + break; + default: + break; + } + + if (pShare) { + pShare->share(info); + } +} + +void MyShareResult::shareResult(EShareResult ret, const char* msg, TShareInfo info) +{ + char shareInfo[1024] = { 0 }; + char shareStatus[1024] = { 0 }; + sprintf(shareStatus, "Share info:%s", (ret == eShareSuccess)? "Successed" : "Failed"); + sprintf(shareInfo, " %s\ntext:%s", + shareStatus, + info.find("text")->second.c_str() + ); + CCMessageBox(shareInfo , msg); +} diff --git a/plugin/samples/HelloSocial/Classes/MyShareManager.h b/plugin/samples/HelloSocial/Classes/MyShareManager.h new file mode 100755 index 0000000000..a8c65eea67 --- /dev/null +++ b/plugin/samples/HelloSocial/Classes/MyShareManager.h @@ -0,0 +1,37 @@ +#ifndef __MY_SHARE_MANAGER_H__ +#define __MY_SHARE_MANAGER_H__ + +#include "SocialTwitter.h" + +class MyShareResult : public cocos2d::plugin::ShareResultListener +{ +public: + virtual void shareResult(cocos2d::plugin::EShareResult ret, const char* msg, cocos2d::plugin::TShareInfo info); +}; + +class MyShareManager +{ +public: + static MyShareManager* sharedManager(); + static void purgeManager(); + + typedef enum { + eNoneMode = 0, + eTwitter, + } MyShareMode; + + void unloadSocialPlugin(); + void loadSocialPlugin(); + void shareByMode(cocos2d::plugin::TShareInfo info, MyShareMode mode); + +private: + MyShareManager(); + virtual ~MyShareManager(); + + static MyShareManager* s_pManager; + + cocos2d::plugin::SocialTwitter* s_pTwitter; + MyShareResult* s_pRetListener; +}; + +#endif // __MY_SHARE_MANAGER_H__ diff --git a/plugin/samples/HelloSocial/Resources/background.png.REMOVED.git-id b/plugin/samples/HelloSocial/Resources/background.png.REMOVED.git-id new file mode 100644 index 0000000000..15b10523a1 --- /dev/null +++ b/plugin/samples/HelloSocial/Resources/background.png.REMOVED.git-id @@ -0,0 +1 @@ +b2e4ae6ce873ef4a74cf0230693ef26e939d2778 \ No newline at end of file diff --git a/plugin/samples/HelloSocial/proj.android/.classpath b/plugin/samples/HelloSocial/proj.android/.classpath new file mode 100755 index 0000000000..2115f0c73a --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/.classpath @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/plugin/samples/HelloSocial/proj.android/.project b/plugin/samples/HelloSocial/proj.android/.project new file mode 100755 index 0000000000..6328a7480a --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/.project @@ -0,0 +1,45 @@ + + + HelloSocial + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + + + Classes + 2 + PARENT-1-PROJECT_LOC/Classes + + + publish + 2 + PARENT-3-PROJECT_LOC/publish + + + diff --git a/plugin/samples/HelloSocial/proj.android/AndroidManifest.xml b/plugin/samples/HelloSocial/proj.android/AndroidManifest.xml new file mode 100755 index 0000000000..dc93dff99a --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/samples/HelloSocial/proj.android/ant.properties b/plugin/samples/HelloSocial/proj.android/ant.properties new file mode 100755 index 0000000000..b0971e891e --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/ant.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked into Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/plugin/samples/HelloSocial/proj.android/build.xml b/plugin/samples/HelloSocial/proj.android/build.xml new file mode 100755 index 0000000000..80abad0ab0 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/samples/HelloSocial/proj.android/build_native.sh b/plugin/samples/HelloSocial/proj.android/build_native.sh new file mode 100755 index 0000000000..01fc562132 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/build_native.sh @@ -0,0 +1,81 @@ +APPNAME="HelloAnalytics" + +# options + +buildexternalsfromsource= + +usage(){ +cat << EOF +usage: $0 [options] + +Build C/C++ code for $APPNAME using Android NDK + +OPTIONS: +-s Build externals from source +-h this help +EOF +} + +while getopts "sh" OPTION; do +case "$OPTION" in +s) +buildexternalsfromsource=1 +;; +h) +usage +exit 0 +;; +esac +done + +# paths + +if [ -z "${NDK_ROOT+aaa}" ];then +echo "please define NDK_ROOT" +exit 1 +fi + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +# ... use paths relative to current directory +PLUGIN_ROOT="$DIR/../../.." +COCOS2DX_ROOT="$DIR/../../../.." +APP_ROOT="$DIR/.." +APP_ANDROID_ROOT="$DIR" + +echo "PLUGIN_ROOT = $PLUGIN_ROOT" +echo "NDK_ROOT = $NDK_ROOT" +echo "COCOS2DX_ROOT = $COCOS2DX_ROOT" +echo "APP_ROOT = $APP_ROOT" +echo "APP_ANDROID_ROOT = $APP_ANDROID_ROOT" +echo "---------------------------------------------------------" + +# make sure assets is exist +if [ -d "$APP_ANDROID_ROOT"/assets ]; then + rm -rf "$APP_ANDROID_ROOT"/assets +fi + +mkdir "$APP_ANDROID_ROOT"/assets + +# copy resources +for file in "$APP_ROOT"/Resources/* +do +if [ -d "$file" ]; then + cp -rf "$file" "$APP_ANDROID_ROOT"/assets +fi + +if [ -f "$file" ]; then + cp "$file" "$APP_ANDROID_ROOT"/assets +fi +done + +if [[ "$buildexternalsfromsource" ]]; then + echo "Building external dependencies from source" + set -x + "$NDK_ROOT"/ndk-build -j 4 -C "$APP_ANDROID_ROOT" $* \ + "NDK_MODULE_PATH=${PLUGIN_ROOT}/publish:${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/source" +else + echo "Using prebuilt externals" + set -x + "$NDK_ROOT"/ndk-build -j 4 -C "$APP_ANDROID_ROOT" $* \ + "NDK_MODULE_PATH=${PLUGIN_ROOT}/publish:${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt" +fi diff --git a/plugin/samples/HelloSocial/proj.android/jni/Android.mk b/plugin/samples/HelloSocial/proj.android/jni/Android.mk new file mode 100755 index 0000000000..3e8cd941a2 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/jni/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := game_shared + +LOCAL_MODULE_FILENAME := libgame + +LOCAL_SRC_FILES := hellocpp/main.cpp \ + ../../Classes/AppDelegate.cpp \ + ../../Classes/HelloWorldScene.cpp \ + ../../Classes/MyShareManager.cpp + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes + +LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static \ + PluginTwitterStatic \ + PluginProtocolStatic + +include $(BUILD_SHARED_LIBRARY) + +$(call import-module,cocos2dx) \ +$(call import-module,plugins/twitter/android) \ +$(call import-module,protocols/android) diff --git a/plugin/samples/HelloSocial/proj.android/jni/Application.mk b/plugin/samples/HelloSocial/proj.android/jni/Application.mk new file mode 100755 index 0000000000..d16d4facd2 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/jni/Application.mk @@ -0,0 +1,2 @@ +APP_STL := gnustl_static +APP_CPPFLAGS += -frtti \ No newline at end of file diff --git a/plugin/samples/HelloSocial/proj.android/jni/hellocpp/main.cpp b/plugin/samples/HelloSocial/proj.android/jni/hellocpp/main.cpp new file mode 100755 index 0000000000..ee1079c797 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/jni/hellocpp/main.cpp @@ -0,0 +1,47 @@ +#include "AppDelegate.h" +#include "platform/android/jni/JniHelper.h" +#include "PluginJniHelper.h" +#include +#include + +#include "HelloWorldScene.h" + +#define LOG_TAG "main" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) + +using namespace cocos2d; + +extern "C" +{ + +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + JniHelper::setJavaVM(vm); + PluginJniHelper::setJavaVM(vm); + + return JNI_VERSION_1_4; +} + +void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h) +{ + if (!CCDirector::sharedDirector()->getOpenGLView()) + { + CCEGLView *view = CCEGLView::sharedOpenGLView(); + view->setFrameSize(w, h); + + AppDelegate *pAppDelegate = new AppDelegate(); + CCApplication::sharedApplication()->run(); + } + else + { + ccDrawInit(); + ccGLInvalidateStateCache(); + + CCShaderCache::sharedShaderCache()->reloadDefaultShaders(); + CCTextureCache::reloadAllTextures(); + CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL); + CCDirector::sharedDirector()->setGLDefaultValues(); + } +} + +} diff --git a/plugin/samples/HelloSocial/proj.android/proguard-project.txt b/plugin/samples/HelloSocial/proj.android/proguard-project.txt new file mode 100755 index 0000000000..b60ae7ea07 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/plugin/samples/HelloSocial/proj.android/project.properties b/plugin/samples/HelloSocial/proj.android/project.properties new file mode 100755 index 0000000000..859630e465 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-8 +android.library.reference.1=../../../../cocos2dx/platform/android/java diff --git a/plugin/samples/HelloSocial/proj.android/res/values/strings.xml b/plugin/samples/HelloSocial/proj.android/res/values/strings.xml new file mode 100755 index 0000000000..320a39b235 --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/res/values/strings.xml @@ -0,0 +1,4 @@ + + + HelloSocial + diff --git a/plugin/samples/HelloSocial/proj.android/src/org/cocos2dx/helloSocial/HelloSocial.java b/plugin/samples/HelloSocial/proj.android/src/org/cocos2dx/helloSocial/HelloSocial.java new file mode 100755 index 0000000000..cc2a90bf8e --- /dev/null +++ b/plugin/samples/HelloSocial/proj.android/src/org/cocos2dx/helloSocial/HelloSocial.java @@ -0,0 +1,43 @@ +/**************************************************************************** +Copyright (c) 2010-2012 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.helloSocial; + +import org.cocos2dx.lib.Cocos2dxActivity; +import org.cocos2dx.lib.Cocos2dxGLSurfaceView; +import org.cocos2dx.plugin.PluginWrapper; + +import android.os.Bundle; + +public class HelloSocial extends Cocos2dxActivity{ + + protected void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + PluginWrapper.init(this); + PluginWrapper.setGLSurfaceView(Cocos2dxGLSurfaceView.getInstance()); + } + + static { + System.loadLibrary("game"); + } +} diff --git a/plugin/tools/config.sh b/plugin/tools/config.sh index 704df1e450..633aa08126 100755 --- a/plugin/tools/config.sh +++ b/plugin/tools/config.sh @@ -1,7 +1,8 @@ #define plugins array export ALL_PLUGINS=("flurry" "umeng" \ "alipay" "nd91" \ -"admob") +"admob" \ +"twitter") # define the plugin root directory & publish target directory export TARGET_DIR_NAME="publish"