Ad shows in Editor but not in store build - logcat included

The ad shows without any issues in the editor however when I build and run through play store internal testing, the ads will not show. There is an error in my logcat however I can not decipher the error after researching.

Can anyone explain or help?

In reward show method
d__5:MoveNext()
System.Runtime.CompilerServices.AsyncVoidMethodBuilder:Start(TStateMachine&)
AdRewardsController:ShowRewarded()
UnityEngine.Events.UnityAction:Invoke()
UnityEngine.Events.UnityEvent:Invoke()
UnityEngine.EventSystems.EventFunction1:Invoke(T1, BaseEventData) UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction1)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchPress(PointerEventData, Boolean, Boolean)
UnityEngine.EventSystems.StandaloneInputModule:ProcessTouchEvents()
UnityEngine.EventSystems.StandaloneInputModule:Process()

AndroidJavaException: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.h.d, parameter userId
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.h.d, parameter userId
at com.unity3d.mediation.RewardedAdShowOptions$S2SRedeemData.(Unknown Source:2)
at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
at com.unity3d.player.UnityPlayer.access$300(Unknown Source:0)
at com.unity3d.player.UnityPlayer$e$1.handleMessage(Unknown Source:95)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:214)
at com.unity3d.player.UnityPlayer$e.run(Unknown Source:20)
at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.AndroidJNISafe.NewObject (System.IntPtr clazz, System.IntPtr methodID, UnityEngine.jvalue[ ] args) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.AndroidJavaObject._Android

Rewarded failed to show: Failed to show - java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.h.d, parameter userId
d__5:MoveNext()
System.Threading.ContextCallback:Invoke(Object)
System.Threading.ExecutionContext:RunInternal(ExecutionContext, ContextCallback, Object, Boolean)
System.Runtime.CompilerServices.MoveNextRunner:Run()
System.Action:Invoke()
System.Threading.ContextCallback:Invoke(Object)
System.Threading.Tasks.AwaitTaskContinuation:RunCallback(ContextCallback, Object, Task&)
System.Threading.Tasks.Task:FinishContinuations()
System.Threading.Tasks.Task:Finish(Boolean)
System.Threading.Tasks.Task1:TrySetException(Object) System.Threading.Tasks.TaskCompletionSource1:TrySetException(Exception)
Unity.Services.Mediation.RewardedAd:OnShowFailed(Object, ShowErrorEventArgs)
System.EventHandler`1:Invoke(Object, TEventArgs)
System.Threading.SendOrPostCallback:Invoke(Object)
UnityEngine.WorkRequest:Invoke()
UnityEngine.UnitySynchronizationContext
AdUnit with adUnitId: Rewarded_Android has already loaded.

Hi @nobluff67 !
This would mean you are passing S2SData, without a userId (passing null). This is not allowed, and S2SData if used has to contain a userId.

Hope this helps :slight_smile:

1 Like

Pause on help.

It might have to do with not having gameid (build version). Editor version doesnt seem to care. Creating another test build now.

You beat me to it:). UserId = gameid maybe?

Hi @nobluff67 ,

The S2S data is used to validate legitimate rewards, to avoid players cheating. Generally the userId is a game specific value used to identify the player getting rewarded. If you do not have a S2S system set up, we recommend you do not pass any values into the Show call (showOptions is an optional parameter for Show).

Let us know if that’s the case for you, thanks.

Not sure about the S2S stuff, don’t really understand what you are saying.

I am using this code from the mediation code generator, is this code good enough or do I need to do something with S2S within this code?

Do I remove the showOptions part of the code? “await ad.ShowAsync(showOptions);”

Do I need S2S for ad mediation? i.e. is it a best practice or can I do without it?

using System;
using Unity.Services.Core;
using Unity.Services.Mediation;
using UnityEngine;

namespace Unity.Example
{
    public class RewardedAdExample
    {
        IRewardedAd ad;
        string adUnitId = "Rewarded_Android";
        string gameId = "XXXXXXXX";

        public async void InitServices()
        {
            try
            {
                InitializationOptions initializationOptions = new InitializationOptions();
                initializationOptions.SetGameId(gameId);
                await UnityServices.InitializeAsync(initializationOptions);

                InitializationComplete();
            }
            catch (Exception e)
            {
                InitializationFailed(e);
            }
        }

        public void SetupAd()
        {
            //Create
            ad = MediationService.Instance.CreateRewardedAd(adUnitId);

            //Subscribe to events
            ad.OnClosed += AdClosed;
            ad.OnClicked += AdClicked;
            ad.OnLoaded += AdLoaded;
            ad.OnFailedLoad += AdFailedLoad;
            ad.OnUserRewarded += UserRewarded;

            // Impression Event
            MediationService.Instance.ImpressionEventPublisher.OnImpression += ImpressionEvent;
        }
     
        public async void ShowAd()
        {
            if (ad.AdState == AdState.Loaded)
            {
                try
                {
                    RewardedAdShowOptions showOptions = new RewardedAdShowOptions();
                    showOptions.AutoReload = true;
                    await ad.ShowAsync(showOptions);
                    AdShown();
                }
                catch (ShowFailedException e)
                {
                    AdFailedShow(e);
                }
            }
        }

        void InitializationComplete()
        {
            SetupAd();
            LoadAd();
        }

        async void LoadAd()
        {
            try
            {
                await ad.LoadAsync();
            }
            catch (LoadFailedException)
            {
                // We will handle the failure in the OnFailedLoad callback
            }
        }

        void InitializationFailed(Exception e)
        {
            Debug.Log("Initialization Failed: " + e.Message);
        }

        void AdLoaded(object sender, EventArgs e)
        {
            Debug.Log("Ad loaded");
        }

        void AdFailedLoad(object sender, LoadErrorEventArgs e)
        {
            Debug.Log("Failed to load ad");
            Debug.Log(e.Message);
        }
     
        void AdShown()
        {
            Debug.Log("Ad shown!");
        }
     
        void AdClosed(object sender, EventArgs e)
        {
            Debug.Log("Ad has closed");
            // Execute logic after an ad has been closed.
        }

        void AdClicked(object sender, EventArgs e)
        {
            Debug.Log("Ad has been clicked");
            // Execute logic after an ad has been clicked.
        }
     
        void AdFailedShow(ShowFailedException e)
        {
            Debug.Log(e.Message);
        }

        void ImpressionEvent(object sender, ImpressionEventArgs args)
        {
            var impressionData = args.ImpressionData != null ? JsonUtility.ToJson(args.ImpressionData, true) : "null";
            Debug.Log("Impression event from ad unit id " + args.AdUnitId + " " + impressionData);
        }
     
        void UserRewarded(object sender, RewardEventArgs e)
        {
            Debug.Log($"Received reward: type:{e.Type}; amount:{e.Amount}");
        }

    }
}

Hey @nobluff67 ,

Thanks for clarifying. To help determine the issue, which version of Unity Mediation are you using?

Thanks!

1 Like

Most recent version, Version 0.5.0-preview.5

I am currently testing with this line of code:

await ad.ShowAsync();

instead of:

await ad.ShowAsync(showOptions);

FYI - await ad.ShowAsync(); works for me. No idea if I am doing this correctly.

Hey @nobluff67 ,

Thanks for providing this extra insight. So far I haven’t been able to reproduce this issue. In Player Settings > Publishing Settings, do you have Custom Main Gradle Template selected or not?

Thanks,

a couple of post up, I got it working by changing:

await ad.ShowAsync();

instead of:

await ad.ShowAsync(showOptions);

I am just not 100% sure of this is a recommended solution.

Hi @nobluff67 ,

Thanks for sharing a solution that worked for you. Nonetheless, the original code snippet should be able to work, if you reply to my question above, we can continue researching the issue.

Thanks!

1 Like

No I don’t, just progaurd-user.txt. I believe I have added to this file since the issue, so I am not sure if this would have solved my specific issue. The additions to the progaurd file did resolve some other google related issues, so maybe they overlap. I will create a new build later on tonight, with the original code - await ad.ShowAsync(showOptions); to see if the issue persists on my side.

8310420--1090344--upload_2022-7-25_15-36-20.png

@DeclanMcPartlin i just tested and the problem still persists, in other words my previous changes to the progaurd file did not make a difference to this specific issue. In the mean time I have removed the showOptions portion of the await ad.ShowAsync(showOptions); As mentioned before, it works when I remove the showOptions, so at least its not halting my production work.

Hey @nobluff67 ,

I’ve just checked with the team and this issue will be handled in the next patch release, thanks again for reaching out and sharing this. For the time being, I’d recommend using Autoreload by providing filler values for S2S like so:

RewardedAdShowOptions showOptions = new RewardedAdShowOptions();
S2SRedeemData s2SData;
s2SData.UserId = "placeholder";
s2SData.CustomData = "placeholder";
showOptions.S2SData = s2SData;
showOptions.AutoReload = true;
await m_RewardedAd.ShowAsync(showOptions);

I’ll let you know in this thread once we have a new release out. Thanks!

1 Like

This works, however I would like to make sure we are not getting our wires crossed. I am using

ShowRewarded() and not ShowRewardedWithOptions(). The ShowRewarded() method was the one that was giving me issues, and the one I changed with your suggested code.

        public async void ShowRewarded()
        {
            Debug.Log("In reward show method");
            Debug.Log("showad " + m_RewardedAd.AdState);
            completeAdWatched = false;
            if (m_RewardedAd?.AdState == AdState.Loaded)
            {
                try
                {
                    //RewardedAdShowOptions showOptions = new RewardedAdShowOptions();
                    //showOptions.AutoReload = true;
                    //await m_RewardedAd.ShowAsync();
                    //Debug.Log("Rewarded Shown!");
                   
                    RewardedAdShowOptions showOptions = new RewardedAdShowOptions();
                    S2SRedeemData s2SData;
                    s2SData.UserId = "placeholder";
                    s2SData.CustomData = "placeholder";
                    showOptions.S2SData = s2SData;
                    showOptions.AutoReload = true;
                    await m_RewardedAd.ShowAsync(showOptions);
                   
                   
                }
                catch (ShowFailedException e)
                {
                    Debug.LogWarning($"Rewarded failed to show: {e.Message}");
                }
            }
        }
       
        public async void ShowRewardedWithOptions()
        {
            if (m_RewardedAd?.AdState == AdState.Loaded)
            {
                try
                {
                    //Here we provide a user id and custom data for server to server validation.
                    RewardedAdShowOptions showOptions = new RewardedAdShowOptions();
                    showOptions.AutoReload = true;
                    S2SRedeemData s2SData;
                    s2SData.UserId = "my cool user id";
                    s2SData.CustomData = "{\"reward\":\"Gems\",\"amount\":20}";
                    showOptions.S2SData = s2SData;

                    await m_RewardedAd.ShowAsync(showOptions);
                    Debug.Log("Rewarded Shown!");
                }
                catch (ShowFailedException e)
                {
                    Debug.LogWarning($"Rewarded failed to show: {e.Message}");
                }
            }
        }

Hey @nobluff67 ,

Sounds fine, the function you use to show is set in your code so you are free to choose.

Thanks again for pointing out this issue!

1 Like