My application is unable to open OpenFeint dashboard methods. The implementation of the native c++ libraries uses cocos2d-x as a graphic library, but it has a handler and a wrapper to allow the use of OpenFeint functions. OpenFeint initialization and non-activity methods work correctly.
When UI dashboard functions such as openLaderBoards or openAchievements are called either from a Jni call or in the Java onCreate initialization, the application crashes.
EDIT: I have tested and it happens to any Activity change I try, even my own new classes.
EDIT2: I have a +100 bounty in a similar question, anyone who comes up with the answer gets it.
Code
Activity:
public class App extends Cocos2dxActivity{
private Cocos2dxGLSurfaceView mGLView;
OpenFeintX m_kOpenFeintX;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// get the packageName,it's used to set the resource path
String packageName = getApplication().getPackageName();
super.setPackageName(packageName);
InternetConnection.setM_kActivity(this);
m_kOpenFeintX = new OpenFeintX( this);
setContentView(R.layout.applayout);
mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.game_gl_surfaceview);
mGLView.setTextField((EditText)findViewById(R.id.textField));
// Testspace for new Activities, OpenFeint or self-made
//
// Intent myIntent = new Intent(this, TestActivity.class);
// startActivityForResult(myIntent, 0);
// Dashboard.open();
// Cocos2d-x scene opens after this
}
static {
System.loadLibrary("TestProject");
// Native library loaded for cocos2d-x
}
Wrapper:
public class OpenFeintX {
private static OpenFeintXHandler ms_kOpenFeintHandler;
public OpenFeintX(Activity kActivity) {
initializeOpenFeint("TestApp", "derp",
"hurr", "6546516516541",
kActivity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
ms_kOpenFeintHandler = new OpenFeintXHandler();
}
public static void openLeaderBoards() {
Message msg = new Message();
msg.what = OpenFeintXHandler.SHOW_LEADERBOARDS;
ms_kOpenFeintHandler.sendMessage(msg);
}
Handler openDashboard function:
private void openLeaderBoards() {
System.out.println("Opening Dashboard");
Dashboard.openLeaderboards();
}
Manifest:
<application
android:debuggable="true"
android:label="#string/app_name">
<activity
android:configChanges="orientation"
android:label="#string/app_name"
android:name=".App"
android:screenOrientation="portrait"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.openfeint.internal.ui.IntroFlow"
android:label=".IntroFlow"
android:configChanges="orientation|keyboardHidden"
android:theme="#style/OFNestedWindow" />
<activity android:name="com.openfeint.api.ui.Dashboard"
android:label=".Dashboard"
android:configChanges="orientation|keyboardHidden"
android:theme="#style/OFNestedWindow"/>
<activity android:name="com.openfeint.internal.ui.Settings"
android:label=".Settings"
android:configChanges="orientation|keyboardHidden"
android:theme="#style/OFNestedWindow"/>
<activity android:name="com.openfeint.internal.ui.NativeBrowser"
android:label=".NativeBrowser"
android:configChanges="orientation|keyboardHidden"
android:theme="#style/OFNestedWindow"/>
</application>
Stacktrace (won't indent in SO):
http://pastebin.com/jsmSbgw4
The answer was easy but complex. When the app changes to a new activity, the nativeOnPause method from cocos2d-x MessageJNI is called. This method is supposed to call a CCApplication::sharedApplication(), but one of my classes had previously called the CCApplication destructor, which cleared the shared singleton to null.
Even though the answer is easy to fix and project specific, I am going to give some advice on what made me find it. Keep in mind that all my tools are windows and cygwin.
First, make Eclipse do the ndk-builds for you on clean.
Rightclick your Project-> Properties -> C/C++ Build. Builder Settings tab, Command
C:\NVPACK\cygwin\bin\bash.exe -c "cd /cygdrive/path/to/project && ./build_script.sh"
Second, setup your debugger.
Using this tutorial. It may take some time and attempts to get there but it is worth it. My adb-server call script is
export ANDROID_NDK_ROOT=/cygdrive/c/NVPACK/android-ndk-r6b/
cd $ANDROID_NDK_ROOT
./ndk-gdb-eclipse --adb=/cygdrive/c/NVPACK/android-sdk-windows/platform-tools/adb --project=/cygdrive/c/project/path --force --verbose
Third, set your logcat in verbose.
UPDATE: This last step can now be skipped as latest versions of Logcat output the class and line for the whole stacktrace.
You will get long stacktraces like the one in my question. To check where the stacktrace errors point follow this other tutorial. My script to access the library is
C:\NVPACK\android-ndk-r6b\toolchains\x86-4.4.3\prebuilt\windows\bin\i686-android-linux-addr2line.exe -C -f -e c:\path\to\project\libMyLib.so
Related
I have empty Splash activity serving as entry point to the Android application and invoking appropriate activities if Branch data is received.
In case of Branch callback error or missing or unrecognized data it invokes default Main activity.
It all works well if device has Internet connectivity, but in case of failure onInitFinished callback is called twice in a row (once with empty data set and once triggering error), invoking Main activity twice.
public class SplashActivity extends AppCompatActivity
{
Branch.BranchReferralInitListener branchCallback;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_activity);
Log.d("XAPP", "Splash");
branchCallback = new Branch.BranchReferralInitListener()
{
#Override
public void onInitFinished(JSONObject referringParams, BranchError error)
{
Log.d("XAPP", "Branch init session");
if (error == null)
{
Log.d("XAPP", referringParams.toString());
// run different activities depending on the parameters
....
else
{
// fallback to Main activity
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
}
}
else
{
Log.i("XAPP", error.getMessage());
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
}
finish();
}
};
}
#Override
protected void onStart()
{
super.onStart();
Log.d("XAPP", "onStart");
Branch branch = Branch.getInstance();
branch.initSession(branchCallback);
}
}
Resulting logcat when application runs without being connected to the Internet (after it has been previously - at some point - opened through Branch deep link and Branch data has been initialized):
D/XAPP: Splash
D/XAPP: onStart
D/XAPP: Branch init session
D/XAPP: {"+is_first_session":false,"+clicked_branch_link":false}
D/XAPP: Branch init session
I/XAPP: Trouble initializing Branch. Branch API Error: poor network connectivity. Please try again later.
Splash activity is declared as singleTask activity and is started only once.
Relevant parts of AndroidManifest:
<uses-permission android:name="android.permission.INTERNET"/>
...
<activity
android:name=".SplashActivity"
android:launchMode="singleTask"
android:label="#string/app_name"
android:theme="#style/AppTheme.FullScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Branch URI Scheme -->
<intent-filter>
<data android:host="open" android:scheme="xxxx"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.FullScreen">
</activity>
Relevant parts of the Gradle:
android {
compileSdkVersion 26
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 15
targetSdkVersion 26
...
dependencies {
compile('io.branch.sdk.android:library:2.14.4') {
exclude module: 'answers-shim'
}
I could solve the issue by making Main activity singleTask or removing the Splash activity altogether - by moving branching into Main activity, but those solutions are not viable options in this particular case.
One of the possible solutions would also be adding some boolean flag to recognize onInitFinished has already been called, but I would like to avoid that one if possible.
My main concern in this situation and actual question is not how to hack the thing to make it work, but why is onInitFinished called twice and is there a flaw in my Branch callback implementation?
I tested with your SplashActivity in a sample app and the callback was fired only once.
Here is my repo.
Please test with this app to check if you can replicate the behavior
In order to compile the app:
1. Add the URI scheme from your Branch dashboard to the Android Manifest
2. Add the Branch key for your app to the Manifest
3. Add your link domain to the app link filter in the Manifest.
Also, I would suggest upgrading the Branch SDK to the latest version i.e. 2.14.4.
If you have a slightly varied implementation, could you either share your Manifest file here. If not, you could also write into integrations#branch.io where the team could help you efficiently.
Single Task launch mode is required!
The reason for this is because if there is no singleTask Activity instance in the system yet, a new one would be created and simply placed on top of the stack in the same Task. If you are using the Single Task mode as is, it should not restart your entire app. The Single Task mode instantiates the Main/Splash Activity only if it does not exist in the Activity Stack. If the Activity exists in the background, every subsequent intent to the Activity just brings it to the foreground.
When I try to create a new activity it says NullPointerException
It says IDE fatal when I tried look into the error from the event log
Oops!! I was doing it wrong
There is no Issue if I create the new Activity this way.
You may not have created entry for intent-filter in manifest.If you are creating both java and layout file separately without directly creating a activity.
Create a java file say Main.java
use following code :
public class Main extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedState)
{
super.onCreate(savedState);
setContentView(R.layout.your_layout);
}
and in manifest add after application tag
<activity
android:name=".Main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Follow the below steps:
Open the folder bin under the directory where you installed your Android Studio.
Open the file "idea.properties" and open it with Notepad++/UltraEdit/other_edit_tools.
Add "disable.android.first.run=true" as the final line and save the file.
Because you have another layout/activity/menu/or other things.
I faced the same issue, it inserts the activity into Manifest but never creates a new file.
Try these things
Try to use another name activity/fragment/...
Delete other unnecessary things/files e.g. from drawable, files created previously in other directories as well.
Try this following things...
Try to Build Your Project.
Try to Clean your Project.
If not work then Restart Project/Android Studio.
If still not work Then try to Add Activity with Right click and Add
New Java Class.
And check SDK is proper
and let me know what happens.
Hope this will helps...(:
I would like to reuse some service layer code in another project. I do want to be able to change one of the member variables the service uses, without having different service code. I don't see how this can be done as I don't "create" the service; the manifest and the system do that. Thus I can't pass something in a constructor.
I have a hard time finding the write words to ask this question, so perhaps a quick example is best. I have a service, such as:
public class MyService extends Service implements MyCommunicatorListener {
ICommunicator _comm = new BlueToothCommunicator(); // great for project 1, not for project 2!
public void shutUpCommunicator() // example of using communicator
{
_comm.Shutup();
}
// MyCommunicatorListener methods
#Override
public void onPageReceived(Page page) { // example of listening to communicator
Log.d(TAG,"onPageReceived");
}
} // class greatly simplified...
All works well. The service is started my virtue of the fact that it's declared in the manifest:
<service android:name="com.acme.servicelayer.MyService" android:process=":remote" >
<intent-filter>
<action android:name="com.acme.servicelayer.MyService" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</service>
I'd like to keep this service code and reuse it another project. In the other project, I don't want to use:
ICommunicator _comm = new BlueToothCommunicator(); // great for project 1, not for project 2!
I want to use:
ICommunicator _comm = new WiFiCommunicator(); // great for project 2, not for project
1!
How can I do this and keep the same code base? Is there someway to pass arguments through the manifest?
Thanks,
Dave
I need to display an Activity written in Java using the Android SDK in my Flex Mobile app. I've seen it done with Map ANEs, but cannot find any example code or anything of the sort. I've already created the Java and ActionScript code necessary for my ANE to work (the activity is created and all the classes, events, and methods needed to truly bridge the Java and AS3 is there), I just cannot figure out how to add it to the stage. I know it cannot be added to the DisplayList and I am fine with it being a stage object.
If it helps at all, I am trying to display video using MediaPlayer (due to MP4 streaming issues when it is done using AS3/Flex).
For Michael (Aug 27, 2012 # 9:44AM MST):
08-27 09:27:07.836: I/CS VideoInit(2567): context is set
08-27 09:27:07.836: I/CS VideoInit(2567): intent is instantiated
08-27 09:27:07.836: I/ActivityManager(349): START {cmp=air.AndroidANETesting2/xi.video.android.extension.VideoActivity u=0} from pid 2567
The very first line of my Activity is
Log.i("CS VideoActivity","Made it inside the activity somehow");
Here is a look at my Java. This is the init function:
VideoInit.context = context;
Log.i("CS VideoInit","context is set");
Intent intent = new Intent( context.getActivity(), VideoActivity.class );
Log.i("CS VideoInit","intent is instantiated");
context.getActivity().startActivity( intent );
Log.i("CS VideoInit","Activity is started");
context.dispatchStatusEventAsync("PLAY", "PLAY");
And here is my VideoActivity onCreate():
super.onCreate(savedInstanceState);
Log.i("CS VideoActivity","Made it inside the activity somehow");
And my Manifest for good measure (just the application section):
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".VideoActivity"
android:label="#string/title_activity_video" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Update (August 27, 2012 # 10:52AM MST)
After further investigation (or trial and error, whatever you want to call it), I decided to throw the startActivity() line into a try{}catch(Throwable e) to see what, if any, errors it was throwing. Interestingly enough, it threw this.
08-27 10:49:41.406: I/CS VideoInit(7786): Unable to find explicit activity class {air.AndroidANETesting2.debug/xi.video.android.extension.VideoActivity}; have you declared this activity in your AndroidManifest.xml?
It would appear I need to recheck my Android Manifest file.
It's actually quite easy.
You need to create a class in an ANE that implements the android.app.Activity, then from a FREFunction, simply use the startActivity function of the base Activity instance from the FREContext.
So in a function, lets start an activity with an Intent:
public class ExampleFunction implements FREFunction
{
#Override
public FREObject call( FREContext context, FREObject[] passedArgs )
{
Intent intent = new Intent( context.getActivity(), ExampleActivity.class );
context.getActivity().startActivity( intent );
}
}
Then in the actual Activity implementation:
public class ExampleActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
// Do your stuff here, like create views, buttons etc
}
}
This activity will display ontop of your application. You can use a static reference to your FREContext to pass events / data back to your application if you wish.
You also need to add activity in your -app.xml inside manifest application-tag:
<application> <activity android:name="package.ExampleActivity"></activity></application>
I want to create a new file in sdcard when the apk is installing...
How or where should I code?
Thanks in advance!
You definitely can not do that. That would introduce all kinds of security concerns. As Ken Y -N said in his answer, the best thing to do would be to detect the first time that your app is opened, and do something there.
Here's an activity class to do this:
public class StartupChoiceActivity extends Activity {
private static final String TAG = StartupChoiceActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences mPrefs = getSharedPreferences("prefs", Context.MODE_PRIVATE);
if(!mPrefs.getBoolean("has_started_before", false)) {
// Do what ever you want to do the first time the app is run
} else {
//Remember our choice for next time
mPrefs.edit().putBoolean("has_started_before", true).commit();
Log.i(TAG, "We've already started the app at least once");
}
//Do what ever we want to do on a normal startup. This is pretty much always mean starting a new activity
startActivity(new Intent(this, MyNormalFirstActivity.class);
finish();
}
}
The only other thing you need to do is make sure this activity is set as your 'Startup' activity in the AndroidManifest.xml. You can do this by putting this code inside your application tag:
<activity android:name=".StartupChoiceActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
You cannot do that; such a feature would be a good way of getting trojans to propagate, for instance.
Just check for the first run of your program and do the initialisation there.