Supporting multiple Install receivers in android application - google-analytics

We had a requirement to support multiple Install receiver in my Android using the following code
<receiver android:name="com.google.android.apps.analytics.AnalyticsReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
But since the INSTALL_REFERRER can be received by only one receiver within the application we a were not able to get the install referrer in other BroadcastReceivers.

You are right. MUltiple Install Receivers aren't supported. But there is a way out.
This article explains how it can be done -> https://mixpanel.com/help/questions/articles/how-can-i-use-multiple-install-trackers-with-the-android-library

You can add your receiver classes in manifest as metadata. See the below code.
<receiver android:name="com.example.android.InstallReferrerReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
<meta-data android:name="Receiver1" android:value="com.example.Receiver1"/>
<meta-data android:name="Receiver2" android:value="com.example.Receiver2"/>
</receiver>

Related

AndroidTV and OPEN_DOCUMENT_TREE Intent

How do I find out if the ACTION_OPEN_DOCUMENT_TREE intent is supported on Android TV?
Targeting API 32 and using the StorageVolume createOpenDocumentTreeIntent call. I can create the intent, but when I attempt to launch it, I get:
"You don't have an app that can do this message".
My app can do that on Android Phones and Tablets, just not AndroidTV. My storage related permissions are:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
For Android TV support, I have added:
<uses-feature android:name="android.software.leanback"
android:required="false" />
<uses-feature android:name="android.hardware.touchscreen"
android:required="false" />
And my TV Activity is declared as:
<activity
android:exported="true"
android:name="com.connectedway.connectedsmb.TvActivity"
android:label="#string/app_name"
android:theme="#style/Theme.Leanback">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
The app comes up on Android TV fine, but when I try to bring up a picker, it fails with the "You don't have an app..." message. I'm thinking there isn't support for this on AndroidTV, but it could be something else.
It looks like Storage Access Framework is not included in Android TV:
https://issuetracker.google.com/issues/202985150
I guess Android TV, is not quite Android.

Flutter : INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI

My flutter app isn't install on Android 12 version. I tried with android:exported, but nothing work. It's show me this type of error-
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk... 3.3s
Error: ADB exited with exit code 1
Performing Streamed Install
adb: failed to install /Users/abir/Documents/Office
Work/MediMate-App-Old-Version/build/app/outputs/flutter-apk/app.apk: Failure
[INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI:
/data/app/vmdl489268217.tmp/base.apk (at Binary XML file line #125):
io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService: Targeting S+ (version 31 and above)
requires that an explicit value for android:exported be defined when intent filters are present]
Error launching application on sdk gphone64 x86 64.
Here is my AndroidManifest.xml file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="care.example.health">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- The Agora SDK requires Bluetooth permissions in case users are using Bluetooth devices.-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:label="example"
android:name="${applicationName}"
android:icon="#mipmap/ic_launcher">
<activity
android:exported="true"
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="#style/NormalTheme"
/>
<intent-filter
android:exported="false">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter
android:exported="false">
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
What did I miss ?
If you get this error message when you try to run your flutter app on android studio emulator, this solved it for me!
Error: ADB exited with exit code 1
Performing Streamed Install
adb: failed to install C:\Users\aasmu\OneDrive\Proskjekt\Flutter_course\flash-chat-flutter\build\app\outputs\flutter-apk\app.apk: Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI: /data/app/vmdl2080833837.tmp/base.apk (at Binary XML file line #28): co.appbrewery.flash_chat.MainActivity: Targeting S+ (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present]
1. Locate your androidManifest.xml
In the right corner of android studio where your project files are follow this path:
'your project name'/android/app/src/main/AndroidManifest.xml
Image showing file path in android studio with yellow highelighter
2. In the AndroidManifest.xml file, find this set of code:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
Image showing the section between the two perpendicular red lines
3. Copy and paste this line somewhere between '<activity' and the next '>'.
android:exported="true"
Image showing the line pasted in between the yellow'<activity' and '<'
Your problem should now be solved!
If your problem persists:
Make sure your flutter doctor checks out, i had mine checked out on everything except Visual studio when i solved this. (type 'flutter doctor' in the android studio terminal)
Check these two things mentioned in this answer. https://stackoverflow.com/a/56417433/14637333
Even I faced the same issue. I'm able to overcome it by adding below code for the particular service directly in the plugin.
android:exported="true"
You can find the plugin code in the below path
your_flutter_sdk_location/.pub-cache/hosted/pub.dartlang.org/package_name
As per your question, your issue is arriving of FlutterFirebaseMessagingService. If you see in log there is already mention that
io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService: Targeting S+ (version 31 and above)
requires that an explicit value for android:exported be defined when intent filters are present]
You just need to delete extra android:exported="false" from intent-filter.
put here as like
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
also update plugin, if they are not updated
firebase_core: ^1.16.0
firebase_messaging: ^11.3.0
add this property to as from android 12 its required to be write this for activity and your device has android api level 31 which is android - 12
android:exported="true"
very simple add this line of code android:exported="true" AndroidManifest.xml
location android/app/src/main/AndroidManifest.xml
if none of the solutions above worked, use the forked version of firebase_messaging: ^6.0.16 with android:exported="false".
firebase_messaging:
git:
url: https://github.com/itsAyyazdev/firebase_messaging.git

Xamarin.Forms FCM OnRefereshToken Method not called in release mode Android Device

I have Implemented a Xamarin Pushnotification using FCM and my code looks like
// This service handles the device's registration with FCM.
[Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class ZCFirebaseIIDService : FirebaseInstanceIdService
{
#region override methods
public override void OnTokenRefresh()
{
var refreshedToken = FirebaseInstanceId.Instance.Token;
App.DeviceToken = FirebaseInstanceId.Instance.Token;
}
#endregion
}
Also I have added all required permission in AndroidManifest and its like
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="App name" android:icon="#drawable/icon">
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.appname.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths">
</meta-data>
</provider>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
it's perfectly fine in Debug mode but when I run the app in release mode OnTokenRefresh method not even called .
can anyone please suggest me how can I resolve this issue.
There is a known bug in FCM that even I faced when I was implementing the same in my android application
Java.Lang.IllegalStateException: Default FirebaseApp is not initialized in this process
Make sure to call FirebaseApp.initializeApp(Context) first.
Which is a bug that you will also find in the Microsoft xamarin website where it shows the implementation of FCM which you can find here
Also, there is a Bugzilla report on the same here.
Steps to solve the issue:
Xamarin only gives you this:
This is a known problem that you can work around by cleaning the solution and rebuilding the project (Build > Clean Solution, Build > Rebuild Solution). For more information, see this forum discussion.
But I recommend you do the following to be sure.
Check if you are receiving notifications when in debug mode.
If not remove bin and obj folders from your Android project.
Clean build your solution and try again
If it works archive the application and in release mode, test if you are receiving notifications.(If it works on one device it will work in all).
Steps for archive can be found here

push notifications not handled by onMessage if received when app closed using IBM MobileFirst Platform 7.0

We are using MFP 7.0.0.00-20150907-1450 and building a hybrid app targeting iOS and Android.
We're using the "send bulk messages" REST API to send broadcast messages.
We've implemented WL.Client.Push.onMessage in our app, and as long as the app is running when the notification is received, it handles the message.
If the application is closed when the notification reaches the phone, the message payload doesn't seem to get to our onMessage implementation.
This behavior is identical between iOS and Android.
I suspect there's a timing issue between our onMessage function being assigned and when the MFP framework is trying to pass the the message into our app.
Some pointers on how we might get the message handled in the case where it was received when the app was closed would be great!
(Below are some details of our setup.)
We're using Angular and had this in our main app module:
if (angular.isDefined(window.WL) && angular.isDefined(window.WL.Client.Push)) {
window.WL.Client.Push.onMessage = function (props, payload) {
console.log('Received push notification in client', JSON.stringify(props), JSON.stringify(payload));
$rootScope.$broadcast('pushNotification', props, payload);
};
}
After noticing this ("You must declare it outside any function.") in the docs for onMessage, I've moved the assignment out to the top of a JavaScript file, outside of even an IIFE. This function doesn't seem to be called, certainly there's no logging and the variable remains undefined:
var lastPushMessage;
function pushMessageRecorder(props, payload) {
lastPushMessage = {
props: props,
payload: payload
};
console.log('MFP: push received: ' + JSON.stringify(lastPushMessage, null, 2));
}
WL.Client.Push.onMessage = pushMessageRecorder;
Our security test (users don't have to log in, just have a app packaged with our keys):
<customSecurityTest name="customTests">
<test realm="wl_antiXSRFRealm" step="1" />
<test realm="wl_authenticityRealm" step="1" />
<test realm="wl_remoteDisableRealm" step="1" />
<test realm="wl_directUpdateRealm" mode="perSession" step="1" />
<test realm="wl_anonymousUserRealm" isInternalUserID="true" step="1" />
<test realm="wl_deviceNoProvisioningRealm" isInternalDeviceID="true" step="2" />
</customSecurityTest>
It looks like I've got it working.
(Mostly. If the app is not running and the user swipes away the notification, or opens the app directly from the launcher, then the notification still doesn't show up in the app.)
There were 2 things that needed doing:
the assignment to WL.Client.Push.onMessage had to be done "outside of any function"
it looks like the value for the string "app_name" in native/res/values/strings.xml is used to locate the app from the push service and make sure the message comes through
The second point still doesn't really make sense to me, but it looks like the intent-filter action android:name value in AndroidManifest.xml is built using these values:
{AndroidManifest.xml:/manifest[#package]}.{res/values/strings.xml:/resources/string[#name="app_name"]}.NOTIFICATION
Since the app_name value is used to build the notification qualifier, it can't have any spaces, which is not so nice for the name of your app that's displayed on the phone.
I've worked around that by adding another variable to the strings.xml file (although I could have just hard coded the name in the AndroidManifest.xml too, and then use that variable as my label.
Here's what's working:
res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MyApp</string>
<string name="app_label">My App</string>
<string name="push_notification_title">My App</string>
<!-- ... -->
</resources>
AndroidManifest.xml:
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.MyProject" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19"/>
<supports-screens android:smallScreens="false" android:normalScreens="true" android:largeScreens="false"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Push permissions -->
<permission android:name="com.MyProject.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="com.MyProject.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="#string/app_label" android:icon="#drawable/icon">
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<activity android:name=".MyApp" android:label="#string/app_name" android:configChanges="orientation|keyboardHidden|screenSize" android:launchMode="singleTask" android:theme="#android:style/Theme.Translucent.NoTitleBar" android:screenOrientation="portrait" android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="com.MyProject.MyApp.NOTIFICATION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<!-- Preference Activity -->
<activity android:name="com.worklight.common.WLSettingActivity" android:label="Worklight Settings"/>
<!-- UI Activity for displaying native dialogs -->
<activity android:name="com.worklight.wlclient.ui.UIActivity"/>
<!-- Push service -->
<!-- In order to use the c2dm library, an application must declare a class with the name C2DMReceiver, in its own package, extending com.google.android.c2dm.C2DMBaseReceiver
It must also include this section in the manifest, replacing "com.google.android.apps.chrometophone" with its package name. -->
<service android:name=".GCMIntentService"/>
<service android:name=".ForegroundService"/>
<!-- Only google service can send data messages for the app. If permission is not set - any other app can generate it -->
<receiver android:name="com.worklight.androidgap.push.WLBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="com.MyProject"/>
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.MyProject"/>
</intent-filter>
</receiver>
</application>
</manifest>

How to display last visible fragment on reopening the app

Following is my use case:
User click on App icon -> MainActivity ->FirstActivity-> SecondActivity
SecondActivity has three fragments i.e. F1, F2, F3
Suppose user is on F1 in SecondActivity, now if user minimizes the app by pressing home button, and then re-launches the app not using App icon but by selecting from the list which gets displayed by long press (don't know the technical name of that )
I have already explored most of the questions and even tried following approach
How to make an android app return to the last open activity when relaunched?
(but this seems to work, in case when i want to re-launch my app from app icon i.e. from launcher):
Following is my activity and fragment lifecycle method invocation logs:
When i minimize the app:
E/SecondActivity﹕ onPause called
E/F1﹕ On Pause
E/F1﹕ OnSaveInstanceState
E/SecondActivity onStop called
On re-open app:
E/FirstActivity﹕ onRestart called
E/FirstActivity﹕ onStart called
E/FirstActivity﹕ onResume called
E/SecondActivity﹕ onDestroy called
E/F1﹕ On Detach
E/FirstActivity﹕ onPause called
E/FirstActivity﹕ onStop called
As per my understanding this should work like following:
onPause of SecondActivity, I need to save the current visible fragment in shared pref
onResume of SecondActivity, I need to pull the fragment name and display that using fragmentManager
But after re-opening app my SecondActivity onResume doesn't gets invoked, instead FirstActivity's onRestart gets called and onDestroy of SecondActivity gets called (as shown above)
After trying lot of options and reading several SO solutions, I am unable to sort this out.
Please suggest, how to handle this, thanks in advance.
Edit:
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".controller.ApplicationLoader"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:alwaysRetainTaskState="true"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".SplashActivity"
android:label="#string/app_name"
android:noHistory="true"
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=".RegistrationActivity"
android:label="#string/title_activity_registration"
android:noHistory="true"
android:screenOrientation="portrait"/>
<activity
android:name=".HomePageActivity"
android:label="#string/title_activity_home_page"
android:noHistory="true"
android:screenOrientation="portrait">
<!--
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
-->
</activity>
<service
android:name=".services.BgService"
android:exported="false"
android:process=":remote" >
<intent-filter>
<action android:name="com.example.bgapp.BackgroundService" />
</intent-filter>
</service>
<receiver android:name=".services.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity android:name=".ProductOverviewActivity"
android:screenOrientation="portrait">
</activity>
<receiver android:name=".receivers.SmsReceiver"
android:screenOrientation="portrait">
<intent-filter android:priority="99999">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<!-- Intent service -->
<service
android:name=".services.WService"
android:exported="false" />
<service android:name=".services.VerifyService" android:exported="false"/>
</application>
</manifest>
Your problem is your use of:
android:noHistory="true"
on RegistrationActivity. As soon as the user presses HOME, that RegistrationActivity is finished. Here's a quote from the documentation on noHistory:
A value of "true" means that the activity will not leave a historical trace. It will not remain in the activity stack for the task, so the user will not be able to return to it.

Resources