Calling startIntentSenderForResult from Fragment (Android Billing v3)

前端 未结 11 1097
广开言路
广开言路 2020-11-29 02:46

The new Android Billing v3 documentation and helper code uses startIntentSenderForResult() when launching a purchase flow. I want to start a purchase flow (and

相关标签:
11条回答
  • 2020-11-29 03:07

    In my case i did onActivityResult in Activity :

    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
    
    
        }
        else {
            Log.d(TAG, "onActivityResult handled by IABUtil.");
        }
    
    }
    

    and same in fragment and it makes in app billing works

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    
        // Pass on the activity result to the helper for handling
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
    
    
        }
        else {
            Log.d(ITEM_SKU, "onActivityResult handled by IABUtil.");
        }
    
    }
    
    0 讨论(0)
  • 2020-11-29 03:18

    I suggest creating some sort of generic handling of this issue in your base activity class if you have access to it.

    For example:

    public abstract class BaseActivity extends Activity {
        private List<ActivityResultHandler> mResultHandlers 
            = new ArrayList<ActivityResultHandler>();
    
        public void registerActivityResultHandler(ActivityResultHandler resultHandler) {
            mResultHandlers.add(resultHandler);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            for (ActivityResultHandler resultHandler : mResultHandlers) {
                resultHandler.handle();
            }
        }
    }
    

    Of course, you'll need to implement ActivityResultHandler interface by your fragments and register them on activity startup.

    0 讨论(0)
  • 2020-11-29 03:19

    Regarding LEO's very helpful 2nd solution above:

    If Google ever fixes the issue with startIntentSenderForResult and it now correctly routes the onActivityResult call to the fragment, then this solution should be future-proofed so that the fragment's onActivityResult doesn't get called twice.

    I would like to propose the following modified solution proposed by LEO.

    In the Fragment's parent Activity implementation:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        boolean handled = false;
    
        // The following is a hack to ensure that the InAppPurchasesFragment receives
        // its onActivityResult call.
        //
        // For more information on this issue, read here:
        //
        // http://stackoverflow.com/questions/14131171/calling-startintentsenderforresult-from-fragment-android-billing-v3
        //
        // Note: If Google ever fixes the issue with startIntentSenderForResult() and
        // starts forwarding on the onActivityResult to the fragment automatically, we
        // should future-proof this code so it will still work.
        //
        // If we don't do anything and always call super.onActivityResult, we risk 
        // having the billing fragment's onActivityResult called more than once for
        // the same result.
        //
        // To accomplish this, we create a method called checkIabHelperHandleActivityResult
        // in the billing fragment that returns a boolean indicating whether the result was 
        // handled or not.  We would just call Fragment's onActivityResult method, except 
        // its return value is void.
        //
        // Then call this new method in the billing fragment here and only call 
        // super.onActivityResult if the billing fragment didn't handle it.
    
        if (inAppPurchasesFragment != null)
        {
            handled = inAppPurchasesFragment.checkIabHelperHandleActivityResult(requestCode, resultCode, data);
        }
    
        if (!handled)
        {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    

    Then in your IAB Fragment's implementation:

    /**
     * Allow the IabHelper to process an onActivityResult if it can
     * 
     * @param requestCode The request code
     * @param resultCode The result code
     * @param data The data
     * 
     * @return true if the IABHelper handled the result, else false
     */
    
    public boolean checkIabHelperHandleActivityResult(int requestCode, int resultCode, Intent data)
    {
        return (iabHelper != null) && iabHelper.handleActivityResult(requestCode, resultCode, data);
    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (!checkIabHelperHandleActivityResult(requestCode, resultCode, data))
        {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
    
    0 讨论(0)
  • 2020-11-29 03:22
    if (requestCode == RC_REQUEST) 
    {
        Intent intent = new Intent(ContainerAvtivity.this,ContainerAvtivity.class);
        startActivity(intent);
        finish();
    }
    

    RC_REQUEST is same as you used to launch purchase flow

    Add this in the onActivityResult of your Activity.The inventory listener will produce the desired result for you.(I know its a temp fix but worked for me)).

    0 讨论(0)
  • 2020-11-29 03:22

    if you want to get callback on your fragment than call super.onActivityResult() from your activity.

    This will call your fragments onActivityResult().

    And don't forget to call startIntentSenderForResult from your fragment context.

    Don't use activity context getActivity().startIntentSenderForResult

    0 讨论(0)
  • 2020-11-29 03:24

    Edit: android.support.v4.app.Fragment now contains a backwards compatible version of startIntentSenderForResult(), so this answer is obsolete.

    Old answer:

    As of support library 23.2.0, modifying the requestCode no longer works: FragmentActivity now keeps track of the requests made by its fragments. I added this method to the FragmentActivity that was hosting the Fragment (code based on FragmentActivity.startActivityFromFragment(Fragment, Intent, int, Bundle)):

    public void startIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags) throws IntentSender.SendIntentException {
        if (requestCode == -1) {
            startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags);
            return;
        }
    
        if ((requestCode & 0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
        }
    
        try {
            Method method = FragmentActivity.class.getDeclaredMethod("allocateRequestIndex", Fragment.class);
            method.setAccessible(true);
            int requestIndex = (int) method.invoke(this, fragment);
            startIntentSenderForResult(intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), fillInIntent, flagsMask, flagsValues, extraFlags);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    

    When calling this, only the passed Fragment will receive the onActivityResult() call.

    0 讨论(0)
提交回复
热议问题