I'm tryng to implement in-app-billing.
When i follow the tutorial and add the lines bellow to my app:
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
i receive the following error:
Error:(216, 45) error: unreported exception IabAsyncInProgressException; must be caught or declared to be thrown
The strange thing is when i replace mHelper.dispose() for mHelper.disposeWhenFinished() it works.
I'm worried cause the same error appears again in
mHelper.launchPurchaseFlow(this,ITEM_SKU,1001,mPurchaseFinishedListener,hpacote);
Thanks
Yes, i'm also waste a lot of time in this because in the Google Tutorial on https://developer.android.com/training/in-app-billing/preparing-iab-app.html the sample is old and buggy. If you want a right sample you have to download TrivialDrive from github https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive that has right corrections.
From TrivialDrive MainActivity:
try {
mHelper.launchPurchaseFlow(this, mSelectedSubscriptionPeriod, IabHelper.ITEM_TYPE_SUBS,oldSkus, RC_REQUEST, mPurchaseFinishedListener, payload);
} catch (IabAsyncInProgressException e) {
complain("Error launching purchase flow. Another async operation in progress.");
setWaitScreen(false);
}
and this is the onDestroy()
#Override
public void onDestroy() {
super.onDestroy();
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.disposeWhenFinished();
mHelper = null;
}
}
i've implemented this without error! ;)
Related
I'm developing some application using Xamarin Forms that has a function of route following. When it is used in real conditions on a vehicle it crashes whithout any logs in spite of the fact that I'm using AppCenter, i.e. in App.xaml.cs OnStart I added
protected async override void OnStart()
{
AppCenter.Start("android=__mycode___" +
"uwp={Your UWP App secret here};" +
"ios={Your iOS App secret here}",
typeof(Analytics), typeof(Crashes));
bool hadMemoryWarning = await Crashes.HasReceivedMemoryWarningInLastSessionAsync();
ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();
if (crashReport != null)
{
Analytics.TrackEvent(crashReport.StackTrace);
}
}
In fact I tested my app in AppCenter by using Crashes.GenerateTestCrash() and got a test crash report. Besides I caught some errors using this approach. But now there is at least one reason that makes my app crash without any messages to AppCenter. Are there any clues how to resolve this problem?
Try using an actual asynchronous event handler.
private event EventHandler onStart = delegate { };
protected override void OnStart() {
onStart += handleStart; //subscribe
onStart(this, EventArgs.Empty); //raise event
}
private async void handleStart(object sender,EventArgs args) {
onStart -= handleStart; //unsubscribe
try {
AppCenter.Start("android=__mycode___" +
"uwp={Your UWP App secret here};" +
"ios={Your iOS App secret here}",
typeof(Analytics), typeof(Crashes));
bool hadMemoryWarning = await Crashes.HasReceivedMemoryWarningInLastSessionAsync();
ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();
if (crashReport != null) {
Analytics.TrackEvent(crashReport.StackTrace);
}
} catch (Exception ex) {
//...handle exception or log as needed
}
}
OnStart is a simple void method and not an actual event handler. This mean that when made async it will become a fire and forget function which wont allow you to catch any exceptions that may have occurred within it.
If it is not caught at startup then it probably means that you are doing something similar somewhere within the app using a non event async void that goes uncaught and is crashing the application.
Start by doing a search for any async void in your code and checking to make sure that it is an actual event handler.
I'm trying to use IPreProcessBuildWithReport and IPostProcessBuildWithReport to add a game object to the scene right before build, and promptly delete it from the scene when the build finishes. The goal is to reduce all that I can from the hierarchy during the development but include these objects during the build.
My issue occurs when the build fails (due to some error), it adds the game object before the build started but never reached the code to delete the game object when it fails.
Is there a similar method to detect when the build fails without building my own build player pipeline? I really don't want to stray away from unity's default build pipeline if I don't need to.
If there was no easy way, I was trying to think if maybe there was a way to track the buildfailed exception or error and run a method if it occurs.
Thanks, let me know what you guys think.
EDIT: As requested, here is an example:
class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
// CALLED BEFORE THE BUILD
public void OnPreprocessBuild(BuildReport report)
{
// Create and add gameobjects to scene
}
// CALLED AFTER THE BUILD
public void OnPostprocessBuild(BuildReport report)
{
// Remove gameobjects from scene once built
}
}
}
PreProcess Interface
PostProcess Interface
I was wondering if there was a possible solution by somehow detecting when this buildexception was thrown and running code following.
EDIT 2: I found this post that has possible solutions, however, it may not be as elegant as I'd prefer. I'll try some things out and report back.
I used the post in the 'EDIT 2' to come up with a decent solution. I don't know if it will work 100% of the time and I would love for someone to correct me if I have chosen a poor solution. This should allow me to run code before the build starts, and if the build fails or succeeds without changing the unity build pipeline.
class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
// CALLED BEFORE THE BUILD
public void OnPreprocessBuild(BuildReport report)
{
// Start listening for errors when build starts
Application.logMessageReceived += OnBuildError;
}
// CALLED DURING BUILD TO CHECK FOR ERRORS
private void OnBuildError(string condition, string stacktrace, LogType type)
{
if (type == LogType.Error)
{
// FAILED TO BUILD, STOP LISTENING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
// CALLED AFTER THE BUILD
public void OnPostprocessBuild(BuildReport report)
{
// IF BUILD FINISHED AND SUCCEEDED, STOP LOOKING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
}
This approach is using a custom build handler, but still uses the default build pipeline.
Use BuildHandler.OnBuildStarted instead of (or in addition to) IPreprocessBuildWithReport for pre-processing. For post-processing use BuildHandler.OnBuildCleanup, which is called when a build completes or fails. Can also be used in conjunction with IPostprocessBuildWithReport.
[InitializeOnLoad]
public class BuildHandler : MonoBehaviour
{
public static event Action OnBuildStarted;
public static event Action OnBuildCleanup;
static BuildHandler()
{
BuildPlayerWindow.RegisterBuildPlayerHandler(Build);
}
private static void Build(BuildPlayerOptions buildOptions)
{
try
{
BuildStarted();
//now start Unity's default building procedure
BuildPlayerWindow.DefaultBuildMethods.BuildPlayer(buildOptions);
}
catch (BuildPlayerWindow.BuildMethodException) { } //logged internally
catch (Exception ex)
{
Exception log = ex.InnerException == null ? ex : ex.InnerException;
Debug.LogException(log);
Debug.LogErrorFormat("{0} in BuildHandler: '{1}'", log.GetType().Name, ex.Message);
}
finally
{
BuildCleanup();
}
}
private static void BuildStarted()
{
try
{
if (OnBuildStarted != null)
OnBuildStarted.Invoke();
}
catch (Exception ex)
{
throw new Exception("OnBuildStarted failed", ex);
}
}
private static void BuildCleanup()
{
if (OnBuildCleanup != null)
{
foreach (Action cleanupBuild in OnBuildCleanup.GetInvocationList())
{
try
{
cleanupBuild.Invoke();
}
catch (Exception ex)
{
Object context = cleanupBuild.Target as Object;
Debug.LogException(ex, context);
Debug.LogWarning("Caught exception while BuildHandler.OnBuildCleanup... Continuing");
}
}
}
}
}
I have a Xamarin.Forms app and I am using FreshMvvm framework.
If I do this from ViewIsAppearing method of FirstPageModel:
CoreMethods.PushPageModel<SecondPageModel>();
I go the "SecondPageModel". Then, when I am in the "SecondPageModel" if I do:
CoreMethods.PopPageModel();
or press hard back button, or press title bar back button not works in Android (anything happens). I am using FreshMasterDetailNavigationContainer.
In iOS it works OK, I get back to FirstPageModel.
This is because ViewIsAppearing will always be called when the page starts displaying on the screen. When you pop the second page then go to the first page, the first page's ViewIsAppearing will fire again. It caused a dead cycle and prohibited your app from returning to the first page.
Add a property to avoid that:
bool isInitialized;
public FirstPageModel()
{
// ...
isInitialized = true;
}
protected async override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
if (isInitialized)
{
await Task.Delay(100);
await CoreMethods.PushPageModel<SecondPageModel>();
isInitialized = false;
}
}
iOS may optimize this process, but I still recommend you to add this judgment statement.
Update:
Call it when your app has reached the main thread.
protected override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
if (isInitialized)
{
Device.BeginInvokeOnMainThread(() =>
{
CoreMethods.PushPageModel<SecondPageModel>();
isInitialized = false;
});
}
}
I am new to Robotium and tried to execute following code to launch an app and perform some functions.
An example would be, launch messaging app on android emulator and send a text message "Hi" to a user "test".
package com.example.android.test;
import com.example.android.NewUserActivity;
import com.jayway.android.robotium.solo.Solo;
import android.test.ActivityInstrumentationTestCase2;
public class NewUserActivityTest extends ActivityInstrumentationTestCase2<NewUserActivity> {
private Solo solo;
public NewUserActivityTest() {
super("com.example.android", NewUserActivity.class);
}
public void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
}
#Override
public void tearDown() throws Exception {
try {
solo.finalize();
} catch (Throwable e) {
e.printStackTrace();
}
getActivity().finish();
super.tearDown();
}
public void sms() throws Exception{
assertTrue(solo.searchText("Messaging"));
solo.clickOnText("Messaging");
assertTrue(solo.searchText("New message"));
solo.clickOnButton("New message");
solo.enterText(0, "Test");
solo.enterText(1, "Hi");
}
}
With this code, Eclipse runs the test cases but I don't see it on emulator. I understand the package here is a dummy one, I want to know If I am doing it wrong?
Test methods that you want to be executed must have the prefix "test", e.g. "testSms".
As suggested in this question GWT - Where should i use code splitting while using places/activities/mappers?, I created an ActivityProxy to nest my activities.
I based my implementation on this http://code.google.com/p/google-web-toolkit/issues/detail?id=5129 (6th comment), with one modification: I added a check on the provider before calling GWT.RunAsync:
if (provider != null)
{
GWT.runAsync(new RunAsyncCallback()
{
#Override
public void onFailure(Throwable reason)
{
// ...
}
#Override
public void onSuccess()
{
ActivityProxy.this.nestedActivity = provider.create();
//...
}
});
}
But for some reason, this doesn't work in release mode: the onFailure methode is never called but my activity is never displayed the first time I use it. If I reload the place, everything display just fine.
Then I realised that doing the following solves the problem:
GWT.runAsync(new RunAsyncCallback()
{
#Override
public void onFailure(Throwable reason)
{
// ...
}
#Override
public void onSuccess()
{
if (provider != null)
{
ActivityProxy.this.nestedActivity = provider.create();
//...
}
}
});
So even if I don't understand why it works, I started using it for all my activities.
I ran into the problem again when I decided to use a generator for my ActivityProxy (to avoid writing a provider for each Activity). The synthax becomes GWT.create(ActivityProxy).wrap(MyActivity.class);
Basically, the generated code looks like this:
if (clazz.getName() == "FooClass")
{
nestedActivity = new FooClass(); //inside a RunAsync
}
if (clazz.getName() == "BarClass")
{
nestedActivity = new BarClass(); //inside a RunAsync
}
And the same problem occurs: my app fails to display my activities the first time they are used.
So simple question : "Why?"