I'm learning how to handle OneSignal Push Notifications on Android devices. The problem is, while the application is closed, when I receive a notification, even though I defined the neccessary functions (I guess) it still opens the "Splash Activity", which is defined as MAIN LAUNCHER in manifest. I need to open a different activity with the payload data in it. The link I've referenced from creating these codes is this and I've seen the reference on this answer. I'm only showing the relevant code since this project is classified.
Here is my Manifest file.
<application
android:name="packageName.CustomAppName"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT"
android:value="DISABLED"/>
<activity
android:name="anotherPackageName.SplashActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="anotherPackageName.PaymentActivity"
android:screenOrientation="portrait" />
<service
android:name="somepackagename.NotificationsForPayment"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE">
<intent-filter>
<action android:name="com.onesignal.NotificationExtender" />
</intent-filter>
</service>
</application>
Here is my application class where I define OneSignal service.
public class CustomAppName extends Application {
private static CustomAppName instance;
public static CustomAppName getInstance() {
return instance;
}
public void onCreate() {
super.onCreate();
OneSignal.startInit(this)
.setNotificationOpenedHandler(new CustomNotificationOpening())
.init();
instance = this;
}
}
Here is my CustomNotificationOpening class.
public class CustomNotificationOpening implements OneSignal.NotificationOpenedHandler {
#Override
public void notificationOpened(OSNotificationOpenResult notification) {
notification.notification.payload.additionalData.names();
JSONObject data = notification.notification.payload.additionalData;
Intent intent = new Intent(CustomAppName.getInstance(), PaymentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("paymentModel", data);
CustomAppName.getInstance().startActivity(intent);
}
And here is my NotificationsForPayment class which extends from NotificationExtenderService.
public class NotificationsForPayment extends NotificationExtenderService {
#Override
protected boolean onNotificationProcessing(OSNotificationReceivedResult notification) {
NotificationExtenderService.OverrideSettings overrideSettings = new NotificationExtenderService.OverrideSettings();
overrideSettings.extender = new NotificationCompat.Extender() {
#Override
public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
// Sets the background notification color to Red on Android 5.0+ devices.
Bitmap icon = BitmapFactory.decodeResource(CustomAppName.getInstance().getResources(),
R.drawable.ic_os_notification_fallback_white_24dp);
builder.setLargeIcon(icon);
return builder.setColor(new BigInteger("FF0000FF", 16).intValue());
}
};
OSNotificationDisplayedResult displayedResult = displayNotification(overrideSettings);
}
I don't really know where I'm doing wrong. While the application is open, when I click the notification I can see that "notificationOpened" function is firing. But when it's closed, since I can't debug the program and the notification opens the splash activity, I knew the time for me was to ask this question because none of the answers I've found worked. Is there any way to open the other activity with specific data from the notification while the application was closed? Any help is appreciated, thank you so much.
Found where the error was.
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT"
android:value="DISABLED"/>
The value was supposed to be "DISABLE", not "DISABLED".
so, the updated code is:-
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT"
android:value="DISABLE"/>
Related
Preconditions
1. App starts with LinkActivity, at this point we have no deep link intent, it's ok.
Main activity launched. There we are able to click the deep link.
By clicking on deep link opens LinkActivity, uri is correct, referringParams json is not empty (ok). But...
When we replaying step 2: uri is correct, but the reffering params are empty: "{}"; All other tries are with the same result.
Only when we pausing the app (for example switching to the recent apps menu) and then returning to the app - deep link works as expected, but only at first try. May be some issues with the session close (but in the current version of the sdk it self controls session close)
public class LinkActivity extends AppCompatActivity {
private static final String TAG = LinkActivity.class.getSimpleName();
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
}
#Override
protected void onStart() {
super.onStart();
Uri uri = getIntent().getData();
Log.w(TAG, "uri: " + uri);
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
Log.w(TAG, "json: " + referringParams);
startActivity(new Intent(LinkActivity.this, MainActivity.class));
}
}, uri, this);
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
public class BranchApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Branch.enableLogging();
Branch.getAutoInstance(this);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.myapp">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".BranchApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".LinkActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="myapp.link"
android:scheme="https" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"/>
<meta-data
android:name="io.branch.sdk.BranchKey"
android:value="#string/branch_io_live_key" />
<meta-data
android:name="io.branch.sdk.BranchKey.test"
android:value="#string/branch_io_test_key" />
<meta-data
android:name="io.branch.sdk.TestMode"
android:value="false" />
</application>
</manifest>
implementation "io.branch.sdk.android:library:2.14.3"
Update:
Even with android:launchMode="singleInstance" for LinkActivity steel reproduces (I don't think this is the case).
Udpate2:
Bhardwaj mentioned that no need to call initSession when we initing Branch via getAutoInstance. But how to get refferingParams from uri in that case?
Update3:
From the Branch.checkIntentForSessionRestart doc:
Check for forced session restart. The Branch session is restarted if
the incoming intent has branch_force_new_session set to true. This is
for supporting opening a deep link path while app is already running
in the foreground. Such as clicking push notification while app in
foreground.
So, My desired behavior is matches this description. But how to force session restart?
You can try as mentioned below :-
Branch.getAutoInstance(this) -> Branch.getAutoInstance(this, true)
Branch.getInstance(context) -> Branch.getInstance()
Do not call initSession when you have getAutoInstance()
if(!initiatedBranchDeepLinks) {
// Configure Branch.io
initiatedBranchDeepLinks = true;
Branch branch = Branch.getInstance();
branch.initSession(new Branch.BranchReferralInitListener(){
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
// params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
// params will be empty if no data found
// ... insert custom logic here ...
String message = "Branch.io onInitFinished. Params: " + referringParams.toString();
Log.d(TAG, message);
} else {
Log.i(TAG, error.getMessage());
}
}
}, this.getIntent().getData(), this);
}
Here is Branch Test Bed app:
https://github.com/BranchMetrics/android-branch-deep-linking/tree/master/Branch-SDK-TestBed
You can use this as a reference and see what you are doing incorrectly.
This could be caused by your Manifest configuration. In your <activity> tag, you should include android:launchMode="singleTask". See this section of our docs. This may explain why you are receiving the parameters the first time, but not receiving them on a re-open.
I've been trying to implement an custom UncaughtExceptionHandler into my application and I've discovered the library Ereza/CustomActivityOnCrash.
I have added all the code as described in the README (https://github.com/Ereza/CustomActivityOnCrash) but I still can't seem to get it to work. When I force my app to crash, a white screen pops up and then immediately disappears.
Any ideas what might be causing this? below is some of my code
AndroidManifest
<activity
android:name="com.test.SplashActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.test.MainActivity"
android:label="MainActivity"
android:screenOrientation="portrait"
android:theme="#style/AppTheme"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="cat.ereza.customactivityoncrash.RESTART" />
</intent-filter>
</activity>
<activity
android:name="com.test.ErrorActivity"
android:label="Error"
android:screenOrientation="portrait"
android:theme="#style/AppTheme"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="cat.ereza.customactivityoncrash.ERROR" />
</intent-filter>
</activity>
Application class
public class TestApplication extends Application {
private static TestApplication mInstance;
private TimeZone usersDefaultTimeZone;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
//Customization for CustomActivityOnCrash
//Show (TRUE) or Hide (FALSE) the stack trace on the error activity
CustomActivityOnCrash.setShowErrorDetails(false);
//Enable Restart (TRUE) 'Restart App' button
//Disable Restart (FALSE) 'Close App' button
CustomActivityOnCrash.setEnableAppRestart(true);
//This sets a custom error activity class instead of the default one.
CustomActivityOnCrash.setErrorActivityClass(ErrorActivity.class);
//This sets a EventListener to be notified of events regarding the error activity,
//CustomActivityOnCrash.setEventListener(new CustomEventListener());
//Specify the Activity to to restart the application
CustomActivityOnCrash.setRestartActivityClass(MainActivity.class);
//Install CustomActivityOnCrash
CustomActivityOnCrash.install(this);
//Now initialize your error handlers as normal
Fabric.with(this, new Crashlytics());
}
public static synchronized TestApplication getInstance() {
return mInstance;
}
static class CustomEventListener implements CustomActivityOnCrash.EventListener{
#Override
public void onLaunchErrorActivity() {
Log.i("BookingApp", "onLaunchErrorActivity()");
Crashlytics.logException(new Exception("Unknown Exception Caught & Error screen displayed to user"));
}
#Override
public void onRestartAppFromErrorActivity() {
Log.i("BookingApp", "onRestartAppFromErrorActivity()");
Answers.getInstance().logCustom(new CustomEvent("Restart After Crash"));
}
#Override
public void onCloseAppFromErrorActivity() {
Log.i("BookingApp", "onCloseAppFromErrorActivity()");
Answers.getInstance().logCustom(new CustomEvent("Close After Crash"));
}
}
}
Hi put following code in Application class and modify as you want for handeling unhandled exceptions:
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable e) {
handleUncaughtException(thread, e);
}
});
}
public void handleUncaughtException(Thread thread, Throwable e) {
e.printStackTrace(); // not all Android versions will print the stack trace automatically
//Work what you want to do....
//start new activity with clearing task
Intent intent = new Intent(this, ActivityClass.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
//end
System.exit(2); // kill off the crashed app
}
Hope this help, I am using in my app... works.
After some more investigation I discovered that this library/code doesn't like being run in debug mode. If I installed the application on my device and launched it from there (rather than using Debug from Android Studio), it seemed to work fine.
This is most likely caused by the ErrorActivity not being specified as part of another process.
From the library documentation, regarding the usage of a custom error activity:
If you use this, the activity must be declared in your AndroidManifest.xml, with process set to :error_activity.
The question can be asked in two ways:
- How I can make some processing of variables and data before launching the main activity?
- How I set the main launcher activity based on some logic? i.e. before viewing an activity from a set of activities, I should retrieve data from preferences. And this should be done only for the 1st usage without preferences activity to be saved in the back button stack.
public static String getProfile(Context context) {
SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
// String profile = mSharedPreferences.getString("pref_profile_list", "-1");
String profile = mSharedPreferences.getString("pref_login_list", "-1");
Log.i(TAG, profile);
return profile;
}
void init() {
String profile = getProfile(this);
Log.i(TAG, "getProfile " + profile);
switch (parseInt(profile)){
case 0:
startActivity(new Intent(this, firstActivity.class));
break;
case 2:
startActivity(new Intent(this, secondActivity.class));
break;
default:
Log.i(TAG, profile);
}
}
Thanks.
You can use the android:name="your class name" inside the <application> tag of the manifest file.
android:name :
The fully qualified name of an Application subclass implemented for the application. When the application process is started, this class is instantiated before any of the application's components.
The subclass is optional; most applications won't need one. In the absence of a subclass, Android uses an instance of the base Application class.
Example:
public class Platform extends Application {
public static String str="";
#Override
public void onCreate() {
super.onCreate();
str="I am executed first";
}
}
To execute Platform before any other application's component add this Platform class to manifest file of your project like below,
<application
android:name="com.example.Platform"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<activity
android:name="com.example.HomeActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Hope it helps.
For reference read http://developer.android.com/guide/topics/manifest/application-element.html
create a activity "UILApplication" for your resource initialization
and in the manifest include that
**android:name="com.example.UILApplication"**
android:label="#string/app_name"
android:theme="#style/Theme.AppCompat.Light.DarkActionBar" >
<activity
android:name="com.example.HomePage"
android:label="#string/app_name"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
........
so that it will execute before your launch activity..
Hope this Helps you
The best option would be to use a Splash Screen.
The Splash Screen can be used for a variety of purposes including loading data, making calls to the server, showing the app logo and applying whatever logic you would want. You can think of it as an Activity which runs before your MainActivity and does the pre-processing, while showing a progress screen to the user.
You can create an Class by extends Application class
PreAppResources.Java
public class PreAppResources extends Application{
public static String execute="execute before mail activity";
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
System.out.println(execute);
}
}
AndroidManifest.xml
<application
android:allowBackup="true"
android:name="com.example.listtt.PreAppResources"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.listtt.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
If its not working please let me know i will try to help you more.
I am trying to achieve following case on Android, but no success:
1) Launch Application (Launcher Activity which is a subclass of Base Activity). The Base Activity has code as follows:
///This is in BaseActivity
#Override
public void onCreate(Bundle instance)
{
super.onCreate(instance);
//Config.isLoggedIn() is a static function.
if(! Config.isLoggedIn())
{
////Config.startLoginActivity is a static function
Config.startLoginActivity(this, getIntent());
finish();
}
}
The Config.startLoginActivity functions is defined as
public static void startLoginActivity(final Context ctx, final Intent finishIntent)
{
Intent i = new Intent(ctx, ItemListActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("FINISH_INTENT", finishIntent);
ctx.startActivity(i);
}
Now, the ItemListActivity contains a list of Items as {Item1, Item2, Item3}. In ItemListActivity, I am saving the passed "finishIntent" as
///This is ItemListActivity onCreate Method
if(getIntent().hasExtra("FINISH_INTENT"))
mFinishIntent = getIntent().getParcelableExtra("FINISH_INTENT");
and the onItemListSelected method is described as follows :
#Override
public void onItemSelected(String id) {
Config.setLogInState(true);
if(mFinishIntent != null)
{
Log.i("ITEMLISTACTIVITY", "Class Name = " + mFinishIntent.getClass().getName());
Log.i("ITEMLISTACTIVITY", "Starting mFinishIntent Activity");
startActivity(mFinishIntent);
finish();
}
}
But the issue is the Main Activity is not being launched again, Android takes me to the home screen instead. While looking for a solution, I saw that Google I/O app has the same implementation and that works flawlessly but in my case it is not. I am unable to figure it out. Please help.
Thanks in Advance.
Manifest File is as follows :
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.app.myapplication.ItemListActivity"
android:label="#string/app_name" >
</activity>
<activity
android:name="com.app.myapplication.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Ok Here is a quick help which works for 100 percent which I'm using not mostly but EVERYTIME! you must past it through intent and in your case here it is how it must look like.
Intent intent = new intent(//name of your activity in which you are at the moment.this, //name of activity to which you want to go.class);
startActivity(intent);
Hope this will help
I want to consume an IntentService for my app to laod data from server in the background thread without intracting with or disturbing application activities.
here is my simple IntentService
public class SearchService extends IntentService {
public SearchService() {
super("SearchService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Tag","service started");
}
}
i start this service in the main Activity of my application
public class ChannelsActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this , SearchService.class);
startService(intent);
}
I also define service attribute in manifest file but it does't work for me i don't know what is the problem
<application
<activity
android:name=".ChannelsActivity"
android:screenOrientation="landscape"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".SearchService"/>
</application>
I am stuck with this problem any help will really helpful for me.
The code you have posted should work. Do you see the debug log "service started" in the logcat window? Although it sounds stupid, the SearchService will run and immediately will shut down because there is no extensive work to do and you will not see the Service in Running Services if that is your goal.
Hope it helps.