‹ Flurry Analytics Doc Home

Flurry Analytics Integration Guide

For the C++ version of cocos2d-x v3.x - (all other versions)

SDK Version

Integration

Open a terminal and use the following command to install the SDKBOX Flurry Analytics plugin. Make sure you setup the SDKBOX installer correctly.

$ sdkbox import flurryanalytics

Important Notice

Please make sure the following settings in your project to make the plugin work well.

Disable App Transport Security

Adding the following entry to the info.plist file:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

It should look like this:

Disable Bitcode support

You have to turn off Bitcode support. If you don't, cocos2d-x will fail to build.

Set your game requires full screen

If your game doesn't support all screen orientations, you will need to check Requires full screen in Xcode. If you do not, your app will fail Apple's submission process.

Whitelist canOpenURL function

This setting depends on what plugins are in your project. You may need to add the required entry to the info.plist, under LSApplicationQueriesSchemes.

JSON Configuration

SDKBOX Installer will automatically inject a sample configuration to your sdkbox_config.json, that you have to modify it before you can use it for your own app

Here is an example of the Google Analytics configuration, you need to replace <API KEY> with your specific Flurry Analytics ID account information. Here is an example adding FlurryAnalytics to iOS:

"FlurryAnalytics":{
            "APIKey":"<API KEY>",
            "AppVersion":"V0.1",
            "Debug":false,
            "Level":2,
            "SessionTimeout":10,
            "CrashReport":true
}

Adding FlurryAnalytics to Android is a bit different as it supports locations, pulse and origin settings. Here is an example adding FlurryAnalytics to Android:

"FlurryAnalytics":{
            "APIKey":"<API KEY>",
            "AppVersion":"V0.1",
            "Debug":false,
            "LogEvent":true,
            "Level":2,
            "SessionTimeout":10,
            "CrashReport":true,
            "LocationReport":true,
            "DefLocationLat":104.06,
            "DefLocationLon":30.67,
            "Pulse":true,
            "Origin":[
                {
                    "OriginName":"sdkbox",
                    "OriginVersion":"v0.1",
                    "OriginParams":{
                        "Key1":"Val1",
                        "Key2":"Val2",
                        "Key3":"Val3"
                    }
                },
                {
                    "OriginName":"sdkbox",
                    "OriginVersion":"v0.1"
                }
            ]
}

Usage

Initialize Flurry Analytics

Initialize the plugin where appropriate in your code. We recommend to do this in the AppDelegate::applicationDidFinishLaunching() or AppController:didFinishLaunchingWithOptions(). Make sure to include the appropriate headers. init() and startSession() are required. Example:

#include "PluginFlurryAnalytics/PluginFlurryAnalytics.h"
AppDelegate::applicationDidFinishLaunching()
{
     sdkbox::PluginFlurryAnalytics::init();
     // start session
     sdkbox::PluginFlurryAnalytics::startSession();
}

Using Flurry Analytics

After initialization you can begin to use the Flurry Analytics functionality. Use logevent where ever you want from your code:

std::string eventName = "test event1";
sdkbox::PluginFlurryAnalytics::logEvent(eventName);

Ending Flurry Analytics (Android only)

When you are finished using FlurryAnalytics or when your games ends. It is necessary to end the FlurryAnalytics session. This is a requirement for Android but optional on iOS. Example:

// end session just valid on android, but it's ok to invoke it on iOS
sdkbox::PluginFlurryAnalytics::endSession();

API Reference

Methods

static bool init ( ) ;

init plugin, must be first invoke

SDKBOX_DEPRECATED ( "setAppVersion" ) static void setAppVersion ( const std::string & version ) ;

Explicitly specifies the App Version that Flurry will use to group Analytics data.

This is an optional method that overrides the App Version Flurry uses for reporting. Flurry will
use the CFBundleVersion in your info.plist file when this method is not invoked.
@note There is a maximum of 605 versions allowed for a single app.

This method must be called prior to invoking #startSession:.
@related function
 Android:   setVersionName(String version)
 iOS:       setAppVersion(NString version)
@deprecated flurry will read veersion number from app itself, if it was not set
static std::string getFlurryAgentVersion ( ) ;

Retrieves the Flurry Agent Build Version.

This is an optional method that retrieves the Flurry Agent Version the app is running under.
It is most often used if reporting an unexpected behavior of the SDK to 
Flurry Support
@note This method must be called prior to invoking #startSession:.

FAQ for the iPhone SDK is located at 
Support Center - iPhone FAQ.
@see #setLogLevel: for information on how to view debugging information on your console.
@return The agent version of the Flurry SDK.
@related function
 Android:   getReleaseVersion()
 iOS:       getFlurryAgentVersion()
static void setShowErrorInLogEnabled ( bool value ) ;

Displays an exception in the debug log if thrown during a Session.

This is an optional method that augments the debug logs with exceptions that occur during the session.
You must both capture exceptions to Flurry and set debug logging to enabled for this method to
display information to the console. The default setting for this method is  NO.
@note This method must be called prior to invoking #startSession:.
@see #setLogLevel: for information on how to view debugging information on your console.

#logError:message:exception: for details on logging exceptions. 

#logError:message:error: for details on logging errors.
@related function
 iOS:       setShowErrorInLogEnabled()
static void setDebugLogEnabled ( bool value ) ;

Generates debug logs to console.

This is an optional method that displays debug information related to the Flurry SDK.
display information to the console. The default setting for this method is  NO
which sets the log level to  FlurryLogLevelCriticalOnly.
When set to  YES the debug log level is set to  FlurryLogLevelDebug
@note This method must be called prior to invoking #startSession:. If the method, setLogLevel is called later in the code, debug logging will be automatically enabled.
@related function
 Android:   setLogEnabled
 iOS:       setDebugLogEnabled()
static void setLogLevel ( FA_FlurryLogLevel value ) ;

Generates debug logs to console.

This is an optional method that displays debug information related to the Flurry SDK.
display information to the console. The default setting for this method is  FlurryLogLevelCritycalOnly.
@note Its good practice to call this method prior to invoking #startSession:. If debug logging is disabled earlier, this method will enable it.
@related function
 Android:   setLogLevel
 iOS:       setLogLevel
static void setSessionContinueSeconds ( float seconds ) ;

Set the timeout for expiring a Flurry session.

This is an optional method that sets the time the app may be in the background before
starting a new session upon resume.  The default value for the session timeout is 10
seconds in the background.
@note This method must be called prior to invoking #startSession:.
@related function
 Android:   setContinueSessionMillis
 iOS:       setSessionContinueSeconds
static void setCrashReportingEnabled ( bool value ) ;

Enable automatic collection of crash reports.

This is an optional method that collects crash reports when enabled. The
default value is  NO.
@note This method must be called prior to invoking #startSession:.
@related function
 Android:   setCaptureUncaughtExceptions
 iOS:       setCrashReportingEnabled
static void startSession ( ) ;

Start a Flurry session for the project denoted by apiKey.

This method serves as the entry point to Flurry Analytics collection.  It must be
called in the scope of  applicationDidFinishLaunching.  The session will continue
for the period the app is in the foreground until your app is backgrounded for the
time specified in #setSessionContinueSeconds:. If the app is resumed in that period
the session will continue, otherwise a new session will begin.
Crash reporting will not be enabled. See #setCrashReportingEnabled: for
more information.
@note If testing on a simulator, please be sure to send App to background via home
button. Flurry depends on the iOS lifecycle to be complete for full reporting.
@see #setSessionContinueSeconds: for details on setting a custom session timeout.
 @related function
  Android:   onStartSession
  iOS:       startSession
static void endSession ( ) ;

end session, just valid on Android

@related function
 Android:    onEndSession()
static bool activeSessionExists ( ) ;

Start a Flurry session for the project denoted by apiKey.

@related function
 Android:    isSessionActive
 iOS:        activeSessionExists
static std::string getSessionID ( ) ;

Start a Flurry session for the project denoted by apiKey.

@related function
Android: getSessionId()
iOS:     getSessionID()
static void pauseBackgroundSession ( ) ;

Pauses a Flurry session left running in background. on valid on iOS

This method should be used in case of #setBackgroundSessionEnabled: set to YES. It can be
called when application finished all background tasks (such as playing music) to pause session.
@see #setBackgroundSessionEnabled: for details on setting a custom behaviour on resigning activity.
@related function
iOS:     pauseBackgroundSession()
static void addOrigin ( const std::string & originName ,
                        const std::string & originVersion ) ;

Adds an SDK origin specified by originName and originVersion.

This method allows you to specify origin within your Flurry SDK wrapper. As a general rule
you should capture all the origin info related to your wrapper for Flurry SDK after every session start.
@see #addOrigin:withVersion:withParameters: for details on reporting origin info with parameters.

@related function
Android: addOrigin (String originName, String originVersion)
iOS:     addOrigin: (NSString >) originName withVersion: (NSString >) originVersion
static void addOrigin ( const std::string & originName ,
                        const std::string & originVersion ,
                        std::map <std::string ,
                        std::string> & parameters ) ;

Adds a custom parameterized origin specified by originName with originVersion and parameters.

This method overrides #addOrigin to allow you to associate parameters with an origin attribute. Parameters
are valuable as they allow you to store characteristics of an origin.
@note You should not pass private or confidential information about your origin info in a
custom origin.

A maximum of 9 parameter names may be associated with any origin. Sending
over 10 parameter names with a single origin will result in no parameters being logged
for that origin.
@related function
Android: addOrigin (String originName, String originVersion, Map< String, String > originParameters)
iOS:     addOrigin: (NSString >) originName withVersion: (NSString >) originVersion withParameters: (NSDictionary >) parameters
static void addOrigin ( const std::string & originName ,
                        const std::string & originVersion ,
                        const std::string & parameters ) ;

just for lua, js binding, have the same function with addOrigin(string, string, map)

static int logEvent ( const std::string & eventName ) ;

Records a custom event specified by eventName.

This method allows you to specify custom events within your app.  As a general rule
you should capture events related to user navigation within your app, any action
around monetization, and other events as they are applicable to tracking progress
towards your business goals.
@note You should not pass private or confidential information about your users in a
custom event.

Where applicable, you should make a concerted effort to use timed events with
parameters (#logEvent:withParameters:timed:) or events with parameters
(#logEvent:withParameters:). This provides valuable information around the time the user
spends within an action (e.g. - time spent on a level or viewing a page) or characteristics
of an action (e.g. - Buy Event that has a Parameter of Widget with Value Golden Sword).
@see #logEvent:withParameters: for details on storing events with parameters. 

#logEvent:timed: for details on storing timed events. 

#logEvent:withParameters:timed: for details on storing timed events with parameters. 

#endTimedEvent:withParameters: for details on stopping a timed event and (optionally) updating
parameters.
that can be easily understood by non-technical people in your business domain.
@return enum FA_FlurryEventRecordStatus for the recording status of the logged event.
@related function
Android: logEvent (String eventId)
iOS:     logEvent:(NSString >)eventName
static int logEvent ( const std::string & eventName ,
                      std::map <std::string ,
                      std::string> & parameters ) ;

Records a custom parameterized event specified by eventName with parameters.

This method overrides #logEvent to allow you to associate parameters with an event. Parameters
are extremely valuable as they allow you to store characteristics of an action. For example,
if a user purchased an item it may be helpful to know what level that user was on.
By setting this parameter you will be able to view a distribution of levels for the purcahsed
event on the Flurrly Dev Portal.
@note You should not pass private or confidential information about your users in a
custom event.

A maximum of 10 parameter names may be associated with any event. Sending
over 10 parameter names with a single event will result in no parameters being logged
for that event. You may specify an infinite number of Parameter values. For example,
a Search Box would have 1 parameter name (e.g. - Search Box) and many values, which would
allow you to see what values users look for the most in your app. 

Where applicable, you should make a concerted effort to use timed events with
parameters (#logEvent:withParameters:timed:). This provides valuable information
around the time the user spends within an action (e.g. - time spent on a level or
viewing a page).
@see #logEvent:withParameters:timed: for details on storing timed events with parameters. 

#endTimedEvent:withParameters: for details on stopping a timed event and (optionally) updating
parameters.
that can be easily understood by non-technical people in your business domain.
@return enum FA_FlurryEventRecordStatus for the recording status of the logged event.
@related function
Android: logEvent (String eventId, Map< String, String > parameters)
iOS:     logEvent:(NSString >)eventName withParameters:(NSDictionary >)parameters;
static int logEvent ( const std::string & eventName ,
                      const std::string & parameters ) ;

just for lua, js binding, have same function with logEvent(string, map)

static int logEvent ( const std::string & eventName , bool timed ) ;

Records a timed event specified by eventName.

This method overrides #logEvent to allow you to capture the length of an event. This can
be extremely valuable to understand the level of engagement with a particular action. For
example, you can capture how long a user spends on a level or reading an article.
@note You should not pass private or confidential information about your users in a
custom event.

Where applicable, you should make a concerted effort to use parameters with your timed
events (#logEvent:withParameters:timed:). This provides valuable information
around the characteristics of an action (e.g. - Buy Event that has a Parameter of Widget with
Value Golden Sword).
@see #logEvent:withParameters:timed: for details on storing timed events with parameters. 

#endTimedEvent:withParameters: for details on stopping a timed event and (optionally) updating
parameters.
that can be easily understood by non-technical people in your business domain.
@return enum FA_FlurryEventRecordStatus for the recording status of the logged event.
@related function
Android: logEvent (String eventId, boolean timed)
iOS:     logEvent:(NSString >)eventName timed:(BOOL)timed;
static int logEvent ( const std::string & eventName ,
                      std::map <std::string ,
                      std::string> & parameters ,
                      bool timed ) ;

Records a custom parameterized timed event specified by eventName with parameters.

This method overrides #logEvent to allow you to capture the length of an event with parameters.
This can be extremely valuable to understand the level of engagement with a particular action
and the characteristics associated with that action. For example, you can capture how long a user
spends on a level or reading an article. Parameters can be used to capture, for example, the
author of an article or if something was purchased while on the level.
@note You should not pass private or confidential information about your users in a
custom event.
@see #endTimedEvent:withParameters: for details on stopping a timed event and (optionally) updating
parameters.
that can be easily understood by non-technical people in your business domain.
@return enum FA_FlurryEventRecordStatus for the recording status of the logged event.
@related function
Android: logEvent (String eventId, Map< String, String > parameters, boolean timed)
iOS:     logEvent:(NSString >)eventName withParameters:(NSDictionary >)parameters timed:(BOOL)timed;
static int logEvent ( const std::string & eventName ,
                      const std::string & parameters ,
                      bool timed ) ;

just for lua, js binding, have the same function with logEvent(string, map, bool)

static void endTimedEvent ( const std::string & eventId ) ;

End a timed event

@related function
Android: endTimedEvent (String eventId)
static void endTimedEvent ( const std::string & eventName ,
                            std::map <std::string ,
                            std::string> & parameters ) ;

Ends a timed event specified by eventName and optionally updates parameters with parameters.

This method ends an existing timed event.  If parameters are provided, this will overwrite existing
parameters with the same name or create new parameters if the name does not exist in the parameter
map set by #logEvent:withParameters:timed:.
@note You should not pass private or confidential information about your users in a
custom event.

If the app is backgrounded prior to ending a timed event, the Flurry SDK will automatically
end the timer on the event. 

#endTimedEvent:withParameters: is ignored if called on a previously
terminated event.
@see #logEvent:withParameters:timed: for details on starting a timed event with parameters.
that can be easily understood by non-technical people in your business domain.
@related function
Android: endTimedEvent (String eventId, Map< String, String > parameters)
iOS:     endTimedEvent:(NSString >)eventName withParameters:(NSDictionary >)parameters;
static void endTimedEvent ( const std::string & eventName ,
                            const std::string & parameters ) ;

just for lua, js binding, have same function with endTimeEvent(string, map)

static void logError ( const std::string & errorID ,
                       const std::string & message ,
                       const std::string & info ) ;

Records an app exception. Commonly used to catch unhandled exceptions.

This method captures an exception for reporting to Flurry. We recommend adding an uncaught
exception listener to capture any exceptions that occur during usage that is not
anticipated by your app.
@see #logError:message:error: for details on capturing errors.
@related function
Android: onError (String errorId, String message, String errorClass)
iOS:     logError:(NSString >)errorID message:(NSString >)message error:nullptr;
static void logPageView ( ) ;

Explicitly track a page view during a session.

This method increments the page view count for a session when invoked. It does not associate a name
with the page count. To associate a name with a count of occurences see #logEvent:.
@see #logAllPageViews for details on automatically incrementing page view count based on user
traversing navigation or tab bar controller.
@related function
Android: onPageView
iOS:     logPageView
static void setUserID ( const std::string & userID ) ;

Assign a unique id for a user in your app.

@note Please be sure not to use this method to pass any private or confidential information
about the user.
@related function
Android: setUserId (String userId)
iOS:     setUserID:(NSString >)userID
static void setAge ( int age ) ;

Set your user's age in years.

Use this method to capture the age of your user. Only use this method if you collect this
information explictly from your user (i.e. - there is no need to set a default value).
@note The age is aggregated across all users of your app and not available on a per user
basis.
@related function
Android: setAge (int age)
iOS:     setAge:(int)age;
static void setGender ( const std::string & gender ) ;

Set your user's gender.

Use this method to capture the gender of your user. Only use this method if you collect this
information explictly from your user (i.e. - there is no need to set a default value). Allowable
values are  @"m" or  @"f"
@note The gender is aggregated across all users of your app and not available on a per user
basis.
                 "u" -1 unknow
                 "m" 1 male
                 "f" 0 female
@related function
Android: setGender (byte gender)
iOS:     setGender:(NSString >)gender;
     static void setReportLocation ( bool reportLocation ) ;

Set whether Flurry should record location via GPS. Defaults to true. valid on Android

@related function
Android: setReportLocation (boolean reportLocation)
static void setLatitude ( double latitude ,
                          double longitude ,
                          float horizontalAccuracy ,
                          float verticalAccuracy ) ;

Set the location of the session.

Use information from the CLLocationManager to specify the location of the session. Flurry does not
automatically track this information or include the CLLocation framework.
@note Only the last location entered is captured per session.

Regardless of accuracy specified, the Flurry SDK will only report location at city level or higher. 

Location is aggregated across all users of your app and not available on a per user basis. 

This information should only be captured if it is germaine to the use of your app.
After starting the location manager, you can set the location with Flurry. You can implement
CLLocationManagerDelegate to be aware of when the location is updated. Below is an example
of how to use this method, after you have recieved a location update from the locationManager.
        no use on Android
        no use on Android
@related function
Android: setLocation (float lat, float lon)
iOS:     setLatitude:(double)latitude longitude:(double)longitude horizontalAccuracy:(float)horizontalAccuracy verticalAccuracy:(float)verticalAccuracy;
static void clearLocation ( ) ;

clear the default location.valid on Android

@related function
Android: clearLocation ()
static void setSessionReportsOnCloseEnabled ( bool sendSessionReportsOnClose ) ;

Set session to report when app closes.valid on iOS

Use this method report session data when the app is closed. The default value is  YES.
@note This method is rarely invoked in iOS >= 3.2 due to the updated iOS lifecycle.
@see #setSessionReportsOnPauseEnabled:
@related function
iOS: setSessionReportsOnCloseEnabled:(bool) sendSessionReportsOnClose
static void setSessionReportsOnPauseEnabled ( bool setSessionReportsOnPauseEnabled ) ;

Set session to report when app is sent to the background.valid on iOS

Use this method report session data when the app is paused. The default value is  YES.
@related function
iOS: setSessionReportsOnPauseEnabled:(bool) setSessionReportsOnPauseEnabled
static void setBackgroundSessionEnabled ( bool setBackgroundSessionEnabled ) ;

Set session to support background execution.valid on iOS

Use this method to enable reporting of errors and events when application is
running in backgorund (such applications have  UIBackgroundModes in Info.plist).
You should call #pauseBackgroundSession when appropriate in background mode to
pause the session (for example when played song completed in background)
Default value is  NO
@see #pauseBackgroundSession for details
continue log events and errors for running session.
@related function
iOS:         setBackgroundSessionEnabled:(bool) setBackgroundSessionEnabled
@
static void setEventLoggingEnabled ( bool value ) ;

Enable custom event logging.

Use this method to allow the capture of custom events. The default value is  YES.
@related function
Android:     setLogEvents (boolean logEvents)
iOS:         setEventLoggingEnabled:(bool) value
static void setPulseEnabled ( bool value ) ;

Enables Flurry Pulse

@note: Please see https://developer.yahoo.com/flurry-pulse/ for more details
@related function
Android:     setPulseEnabled (boolean isEnabled)
iOS:         setPulseEnabled:(BOOL)value;
static void setListener ( FlurryAnalyticsListener * listener ) ;

set listener for session callback

static FlurryAnalyticsListener * getListener ( ) ;

get listener

static void removeListener ( ) ;

remove listener, just set null, will not delete it the user should delete listener self

Listeners

void flurrySessionDidCreateWithInfo ( std::map <std::string ,
                                      std::string> & info );

Invoked when analytics session is created,

This method informs the app that an analytics session is created.
@see Flurry#startSession for details on session.

Manual Integration

If the SDKBOX Installer fails to complete successfully, it is possible to integrate SDKBOX manually. If the installer complete successfully, please do not complete anymore of this document. It is not necessary.

These steps are listed last in this document on purpose as they are seldom needed. If you find yourself using these steps, please, after completing, double back and re-read the steps above for other integration items.

Manual Integration For iOS

Drag and drop the following frameworks from the plugins/ios folder of the FlurryAnalytics bundle into your Xcode project, check Copy items if needed when adding frameworks:

sdkbox.framework

PluginFlurryAnalytics.framework

The above frameworks depend upon other frameworks. You also need to add the following system frameworks, if you don't already have them:

Security.framework

SystemConfiguration.framework

AdSupport.framework

Manual Integration For Android

SDKBOX supports three different kinds of Android projects command-line, eclipse and Android Studio.

Copy Files

Copy the following jar files from plugin/android/libs folder of this bundle into your project's /libs folder.

FlurryAnalytics-5.5.0.jar

PluginFlurryAnalytics.jar

sdkbox.jar

Copy jni libs

Copy and overwrite all the folders from plugin/android/jni to your <project_root>/jni/ directory.

2.2 Edit AndroidManifest.xml

Include the following permissions above the application tag:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

To enable hardware acceleration in your application tag. This tag is optional on newer SDK versions and doesn't work on version 2.3.3.

<android:hardwareAccelerated="true" />

2.3 Edit Android.mk

Edit <project_root>/jni/Android.mk to:

Add additional requirements to LOCAL_WHOLE_STATIC_LIBRARIES:

LOCAL_WHOLE_STATIC_LIBRARIES += PluginFlurryAnalytics
LOCAL_WHOLE_STATIC_LIBRARIES += sdkbox

Add a call to:

$(call import-add-path,$(LOCAL_PATH))

before any import-module statements.

Add additional import-module statements at the end:

$(call import-module, ./sdkbox)
$(call import-module, ./pluginflurryanalytics)

This means that your ordering should look similar to this:

$(call import-add-path,$(LOCAL_PATH))
$(call import-module, ./sdkbox)
$(call import-module, ./pluginflurryanalytics)

Note: It is important to make sure these statements are above the existing $(call import-module,./prebuilt-mk) statement, if you are using the pre-built libraries.

Modify Application.mk (Cocos2d-x v3.0 to v3.2 only)

Edit <project_root>/jni/Application.mk to make sure APP_STL is defined correctly. If Application.mk contains APP_STL := c++_static, it should be changed to:

APP_STL := gnustl_static

Modify AppActivity.java

Plugin >= 2.4.0.3

  1. Find the AppActivity.java
find . -name "AppActivity.java"
  1. Replace extends Cocos2dxActivity with extends com.sdkbox.plugin.SDKBoxActivity

Example of the directory where the AppActivity.java file is located:

cpp
  - proj.android/src/org/cocos2dx/cpp/AppActivity.java
  - proj.android-studio/app/src/org/cocos2dx/cpp/AppActivity.java
  - proj.android/app/src/org/cocos2dx/cpp/AppActivity.java ( from cocos2d-x 3.17)

lua
  - frameworks/runtime-src/proj.android/src/org/cocos2dx/lua/AppActivity.java
  - frameworks/runtime-src/proj.android-studio/app/src/org/cocos2dx/lua/AppActivity.java
  - frameworks/runtime-src/proj.android/app/src/org/cocos2dx/lua/AppActivity.java (from cocos2d-x 3.17)

js
  - frameworks/runtime-src/proj.android/src/org/cocos2dx/javascript/AppActivity.java
  - frameworks/runtime-src/proj.android/app/src/org/cocos2dx/javascript/AppActivity.java ( from cocos2d-x 3.17)

Plugin < 2.4.0.3

Note: When using Cocos2d-x from source, different versions have Cocos2dxActivity.java in a different location. One way to find the location is to look in proj.android/project.properties. Example: android.library.reference.1=../../cocos2d-x/cocos/platform/android/java

In this case, Cocos2dxActivity.java should be located at:

../../cocos2d-x/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxActivity.java
import android.content.Intent;
import com.sdkbox.plugin.SDKBox;
onLoadNativeLibraries();
SDKBox.init(this);
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
          if(!SDKBox.onActivityResult(requestCode, resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
          }
    }
    @Override
    protected void onStart() {
          super.onStart();
          SDKBox.onStart();
    }
    @Override
    protected void onStop() {
          super.onStop();
          SDKBox.onStop();
    }
    @Override
    protected void onResume() {
          super.onResume();
          SDKBox.onResume();
    }
    @Override
    protected void onPause() {
          super.onPause();
          SDKBox.onPause();
    }
    @Override
    public void onBackPressed() {
          if(!SDKBox.onBackPressed()) {
            super.onBackPressed();
          }
    }

Proguard (optional)

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# flurry
-keep class com.flurry.** { *; }
-dontwarn com.flurry.**
-keepattributes *Annotation*,EnclosingMethod,Signature
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Google Play Services library
-keep class * extends java.util.ListResourceBundle {
    protected Object[][] getContents();
}

-keep class com.google.protobuf.** { *; }
-dontwarn com.google.protobuf.**

-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
    public static final *** NULL;
}

-keepnames @com.google.android.gms.common.annotation.KeepName class *

-keepclassmembernames class * {
    @com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

#If you are using the Google Mobile Ads SDK, add the following:
# Preserve GMS ads classes
-keep class com.google.android.gms.** { *;
}
-dontwarn com.google.android.gms.**


#If you are using the InMobi SDK, add the following:
# Preserve InMobi Ads classes
-keep class com.inmobi.** { *;
}
-dontwarn com.inmobi.**
#If you are using the Millennial Media SDK, add the following:
# Preserve Millennial Ads classes
-keep class com.millennialmedia.** { *;
}
-dontwarn com.millennialmedia.**



# cocos2d-x
-keep public class org.cocos2dx.** { *; }
-dontwarn org.cocos2dx.**
-keep public class com.chukong.** { *; }
-dontwarn com.chukong.**

# google play service
-keep public class com.google.android.gms.** { public *; }
-dontwarn com.google.android.gms.**

-keep class * extends java.util.ListResourceBundle {
    protected Object[][] getContents();
}

-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
    public static final *** NULL;
}

-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
    @com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

#sdkbox
-keep class com.sdkbox.** { *; }
-dontwarn com.sdkbox.**

Note: Proguard only works with Release builds (i.e cocos run -m release) debug builds do not invoke Proguard rules.