Is there any way to detect when the user taps on the interstitial ads? I tried but did not find any callbacks for detecting interstitial ad clicks.
Any workaround for detecting the same would also be very helpful.
I want to detect ads click to prevent users from generating fake clicks for interstitial ads.
Google added back the removed interstitialAd callback onAdClicked() on SDK 20.4.0. Looks like they removed it and 6 months later realized they messed up and decided to add it back :)
Added the onAdClicked() callback to FullScreenContentCallback.
See the AdMob SDK release notes for details.
I’ve found that upgrading AdMob SDK to the latest version is a must.
You can utilize the combination of ActivityLifecycleCallbacks and WindowCallback.
The ActivityLifecycleCallbacks enables you to observe every Activity lifecycle event that occurs in your app. All in one place.
The WindowCallback enables you to intercept many window events. One of the events that gets fired by the system that we are particularly interested in is dispatchTouchEvent.
Now, here is the strategy:
Register our GlobalActivityLifecycleListener in the Application class
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(GlobalActivityLifecycleListener())
}
}
Check if the currently displayed Activity is an Ad Activity. If yes, register our AdWindowCallbacks
class GlobalActivityLifecycleListener : Application.ActivityLifecycleCallbacks {
//...
override fun onActivityResumed(activity: Activity) {
if (isAdActivity(activity)) {
registerWindowCallbacks(activity)
}
}
private fun registerWindowCallbacks(activity: Activity) {
val currentWindow = activity.window
/*This is needed to forward the events from our callback back to the original
callback after we are done with the processing*/
val originalCallbacks = currentWindow.callback
currentWindow.callback = AdWindowCallbacks(originalCallbacks)
}
}
Intercept/process user touch events
class AdWindowCallbacks(private val originalCallback: Window.Callback) : Window.Callback {
//...
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
//TODO process user touch event
return originalCallback.dispatchTouchEvent(event)
}
}
From there, you can detect the common gestures and act accordingly.
I understand your point.
But technically there is no way to track the Interstitial ad clicks by
user.
If you closely monitor the behavior, these ads are opened in a new page within your app. You can confirm them by logging onPause in your calling Activity.
And when user performs clicks on these ads, they are taken to respective destination either to Play Store or URL opened in mobile browser depending on the nature of the Ads.
As mentioned in comment section by #Daxesh Vekaria, you can set Frequency capping in your AdMob console
or try some other solution as suggested by #FreeLearning
EDIT 1 :
In worst case, you can try implementing fullScreenContentCallback. But as per the documentation it doesn't provide any click callbacks.
Related
I have two activities one with a login screen and the other is the app home screen, what I want is: after successful login, it quickly start a new activity and login page doesn't appear on return back from login.
Have you considered using Fragments instead of Activities?
You can use a navController to manage your views shown.
https://developer.android.com/topic/libraries/architecture/navigation/
For example something like this in your Activity (untested):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navController = Navigation.findNavController(this#MainActivity, R.id.fragment_container)
// Check if user is logged in
if (UserRepository.isLoggedIn()) {
navController.navigate(< the other fragment id >)
} else {
navController.navigate(< the login fragment id >)
}
}
If you don't want to use this, you can also do the redirection in your Application class using startActivity(Intent(baseContext, XXActivity::class.java)) after you checked your login state. That might take some time, so you also wanna add a splash screen -> which I don't recommend, because you cannot really give feedback to the user what's happening and so on.
To prevent back navigation when the login screen was shown, you override the back button:
override fun onBackPressed() {
// Do nothing or manually navigate / close app
}
I would recommend you to go with the Activity/Fragment/NavController approach.
I'm wondering, are there any way to disable analytics auto activity tracking?
I have view hierarchy based on fragments and there are few cases:
Activity that have one fragment always.
Activity that can have different fragments as root.
Activity with root fragment, that contains ViewPager with other fragments.
I use such a code in fragments from Firebase docs to track custom screens:
mFirebaseAnalytics.setCurrentScreen(getActivity(), "some_fragment_1", null);
In first case, I want to track only root fragment.
In second case, I want to track only each fragment that becomes root.
In third case, I want to track only each fragment that becomes visible in ViewPager.
And, the problem is, that I don't want to track Activities at all, but unfortunately, Firebase do it on its own - as a result of that, my statistics looks weird, like:
SomeActivity 50%
some_fragment_1 30%
some_fragment_2 20%
I dont't need activity in this statistics, because, fragment statistics already includes it.
So, is there any way to disable activity tracking?
Now it's possible with new API to manually track screens.
Can disable auto-tracking
On iOS, set FirebaseAutomaticScreenReportingEnabled to NO in your info.plist. On Android, set google_analytics_automatic_screen_reporting_enabled to false in your manifest.
Manual Tracking
iOS
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// After enough time has passed to make this screen view significant.
Analytics.logEvent(AnalyticsEventScreenView, parameters: [
AnalyticsParameterScreenName: screenName!,
AnalyticsParameterScreenClass: screenClass!,
MyAppAnalyticsParameterFitnessCategory: category!
])
}
Android
#Override
public void onResume() {
super.onResume();
// After enough time has passed to make this screen view significant.
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, screenName);
bundle.putString(FirebaseAnalytics.Param.SCREEN_CLASS, screenClass);
bundle.putString(MyAppAnalyticsConstants.Param.TOPIC, topic);
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle);
}
https://firebase.googleblog.com/2020/08/google-analytics-manual-screen-view.html
I know that this is rather a hack, but seems to be working with latest firebase analytics. The idea is that, Firebase Analytics uses registerActivityLifecycleCallbacks() internally on each activity declared in the manifest, so disabling that way disables auto-activity reporting.
Place that code in each root Activity you are using.
#Override
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
// com.google.android.gms.measurement.internal.zzfl for firebase-core:17.1.0, play-services-measurement-impl:17.1.0
if (!callback.getClass().getName().startsWith("com.google.android.gms.measurement.")){
super.registerActivityLifecycleCallbacks(callback);
}
}
Credits for finding that goes to #liudongmiao on https://github.com/firebase/quickstart-android/issues/370.
To disable screen auto-tracking in Firebase Analytics 17.5.0, I had to catch callback registrations in my Application class, not in individual activities, and the callback class name has changed again:
#Override
public void registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback) {
if (!callback.getClass().getName().startsWith("com.google.android.gms.internal.measurement.")){
super.registerActivityLifecycleCallbacks(callback);
}
}
Unfortunately, contrary to what Google's documentation states (https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event#SCREEN_VIEW), I wasn't able to manually tag screen views by logging the event FirebaseAnalytics.Event.SCREEN_VIEW. For now I've resorted to logging screen views with a custom event.
I am using MvvmCross for my Xamarin.Android Application. I am using Messenger for Communication between my Service and ViewModel. Eg: HomeViewModel has a Subscription for ItemRefresh Method. I used to Publish from Service for any change in Items. Below is the example code snippet.
public class HomeViewModel
{
private MvxSubscriptionToken _updatedItemToken;
public HomeViewModel()
{
_updatedItemToken = messenger.Subscribe<UpdatedItemMessage>(ItemUpdated);
}
public void ItemUpdated(UpdatedItemMessage message)
{
//my code to refresh the page.
}
}
What is the Problem now?
Everything is working fine until I Introduce logout feature.
During Logout, Irrespective of where you are in the app, I need to clear all the activities from navigation stack and navigate to login page
After Logout, If I goes to HomeViewModel, The Subscription added again and the messages doubled up (hitting twice on each publish message).
What I have tried?
Purge the Subscription On Logging out. using _messenger.RequestPurgeAll();
Tried purging individual message like below
if(_messenger.HasSubscriptionsFor())
{
messenger.RequestPurge(typeof(UpdatedItemMessage));
}
Unsubscribe the Message OnDestroy(). It works well on navigations of the page but not during logout. Logout will clear all activities immediately which will not call OnDestroy of every Visible Activities. Logout code is below.
var intent = new Intent(this, typeof(LoginView));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);
StartActivity(intent); Finish();
Any help would be appreciated? I don't understand the use of RequestPurge which should ideally help for me but not.
Have you tried disposing the MvxSubscriptionToken you get from the messenger?
In your case:
_updatedItemToken.Dispose();
This should make the subscription go away.
Here is my scenario: when my app gets purged from memory by the OS and its reopened from the recent apps list, it goes straight to the Activity that was last open. When this happens I would like to initialize a couple of business objects.
My first approach to achieve this was to do the initialization in the InitializeLastChance method in the Setup class.
Inside the InitializeLastChance method I check if the current top activity is the MvxSplashScreenActivity. If it's not, I make the necessary initialization. The code is something like this:
protected override void InitializeLastChance()
{
try
{
var topActivity = Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
if (topActivity.LocalClassName != _splashScreenName)
{
//Do special initialization
}
}
catch (Exception ex)
{
//Log error
}
base.InitializeLastChance();
}
This works as expected but the visual effect isn't the best: a blank screen with the name of the app appears for a couple of seconds while the initialization occurs. When the initialization is finished, the last open activity is loaded.
To avoid this blank screen, I wanted to try a different approach: show an Activity while the initialization is being done, similar to a splash screen, so that the user can have some feedback that something is happening. In this approach the ViewModel attached to the new Activity would do the initialization that I want.
To show this new activity, I tried creating a custom IMvxAppStart and register it in the App class, but that hasn't worked. My custom IMvxAppStart has the following code:
public class CustomAppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
if (hint == null)
{
ShowViewModel<LoginViewModel>();
}
else
{
ShowViewModel<InitializationViewModel>();
}
}
}
I wanted to show the LoginViewModel when the app starts from scratch and in the cases where the app goes straight to the last loaded Activity, the InitializationViewModel would be shown. In the latter scenario the Start method isn't called. I've checked the MvvmCross source code and as far as I can understand, the Start method is called by the MvxSplashScreenActivity (correct me if I'm wrong). When an app is reopened and goes straight to the last opened Activity, the MvxSplashScreenActivity isn't used so the Start method in CustomAppStart is not called.
That being said, I have some questions regarding the CustomAppStart approach:
Is this approach the best way to show a splash screen or "initialization activity" in the cases where the app goes straight to the last opened activity?
How do I use the CustomAppStart in these situations, since it seems that the Start method is called only from the MvxSplashScreenActivity?
How do I pass a value to the hint parameter in the Start method?
Thanks
I noticed that my app was receiving few clicks on the InterstitialAd, and I saw that the Ad could be instantly closed by pressing the Back button. Usually the ad takes a few seconds to appear, so the user can close it even before seeing it (when only a black screen appears).
I don't think that it's fair, is almost useless to show it. Is there anyway to prevent this from happening?
I did this, but nothing happened...
// When creating the InterstitialAd, I set the following listener
mInterstitial.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
isShowingInterstitialAd = true;
mInterstitial.show();
}
#Override
public void onAdClosed() {
isShowingInterstitialAd = false;
mAdView.setVisibility(View.VISIBLE);
mAdViewClose.setVisibility(View.VISIBLE);
}
});
// On the Activity's class
#Override
public void onBackPressed() {
if (isShowingInterstitialAd) {
return;
}
// ...
}
My understanding is that AdMob draws its own Activity on top of yours, so it has its own implementation of onBackPressed(), which means that you don't have control of anything that happens once you call mInterstitial.show(); until AdMob gives control back to your activity.
Don't sweat the little things like this.
You are much better off spending energy making your app better.
Some people will never click on ads. But if you provide an inapp purchase that removes the ads they may well buy that. That is a better return on investment for your dev effort.
IMHO
Depending on your OS, there are a few ways to override that back button. Search for back button override to find them.