Giter Site home page Giter Site logo

adaptyteam / adaptyui-flutter Goto Github PK

View Code? Open in Web Editor NEW
11.0 11.0 4.0 874 KB

Extension to the Adapty SDK that allows you to easily add purchase screens to your application.

Home Page: https://docs.adapty.io/docs/paywall-builder-getting-started

License: MIT License

Kotlin 11.50% Ruby 2.72% Swift 36.14% Objective-C 0.97% Dart 48.66%

adaptyui-flutter's People

Contributors

vladd-g avatar x401om avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

adaptyui-flutter's Issues

paywallViewDidFinishPurchase is never triggered on iOs

The paywallViewDidFinishPurchase handler in AdaptyUIObserver is correctly triggered at the end of the purchase on Android, but on iOs it's never triggered.

All the test that I did were in sandbox environment.

My flutter doctor output is the following:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.13.7, on macOS 13.6 22G120 darwin-arm64, locale it-IT)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
[✓] Android Studio (version 2022.3)
[✓] IntelliJ IDEA Community Edition (version 2022.2.3)
[✓] VS Code (version 1.83.0)
[✓] Connected device (2 available)
[✓] Network resources

• No issues found!

The pubspec.yaml contains the following dependencies version:

adapty_flutter: ^2.7.0
adapty_ui_flutter: ^2.0.1

Here you can find a sample app to reproduce the bug.

import 'package:adapty_flutter/adapty_flutter.dart';
import 'package:adapty_ui_flutter/adapty_ui_flutter.dart';
import 'package:flutter/material.dart';

class CustomAdaptyUIObserver extends AdaptyUIObserver {
  @override
  void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) {
    switch (action.type) {
      case AdaptyUIActionType.close:
      case AdaptyUIActionType.androidSystemBack:
        view.dismiss();
        break;
      case AdaptyUIActionType.openUrl:
      default:
        break;
    }
  }

  @override
  void paywallViewDidSelectProduct(
      AdaptyUIView view, AdaptyPaywallProduct product) {
    debugPrint("paywallViewDidSelectProduct");
  }

  @override
  void paywallViewDidStartPurchase(
      AdaptyUIView view, AdaptyPaywallProduct product) {
    debugPrint("paywallViewDidStartPurchase");
  }

  @override
  void paywallViewDidCancelPurchase(
      AdaptyUIView view, AdaptyPaywallProduct product) {
    debugPrint("paywallViewDidCancelPurchase");
  }

  @override
  void paywallViewDidFinishPurchase(
      AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile) {
    // this is never printed
    debugPrint("paywallViewDidFinishPurchase");

    view.dismiss();
  }

  @override
  void paywallViewDidFailPurchase(
      AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error) {
    debugPrint("paywallViewDidFailPurchase");
  }

  @override
  void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile) {
    debugPrint("paywallViewDidFinishRestore");
  }

  @override
  void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) {
    debugPrint("paywallViewDidFailRestore");
  }

  @override
  void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error) {
    debugPrint("paywallViewDidFailRendering");
  }

  @override
  void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyError error) {
    debugPrint("paywallViewDidFailLoadingProducts");
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late Adapty adapty;
  late AdaptyUI adaptyUI;

  @override
  void initState() {
    super.initState();

    adapty = Adapty();
    adapty.activate();

    adaptyUI = AdaptyUI();

    adaptyUI.addObserver(CustomAdaptyUIObserver());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            child: const Text("Paywall"),
            onPressed: () async {
              final paywall = await adapty.getPaywall(
                id: "PLACEMENT_ID",
              );
              final AdaptyUIView view = await adaptyUI.createPaywallView(
                paywall: paywall,
                locale: 'en',
              );
              await view.present();
            },
          ),
        ),
      ),
    );
  }
}

Error: Type 'AdaptyIOSProductsFetchPolicy' not found.

On version 1.1.0 of the package, the class AdaptyIOSProductsFetchPolicy is not defined. The error is also declared on the
pub dev package page.

The stacktrace obtained is the following:

- 'AdaptyUI' is from 'package:adapty_ui_flutter/src/adaptyui.dart' ('../../.pub-cache/hosted/pub.dev/adapty_ui_flutter-1.1.0/lib/src/adaptyui.dart').
adaptyui.dart:1

Try correcting the name to the name of an existing getter, or defining a getter or field named 'AdaptyIOSProductsFetchPolicy'.
              fetchPolicy = AdaptyIOSProductsFetchPolicy.defaultPolicy;
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: Error: 'AdaptyIOSProductsFetchPolicy' isn't a type.
adaptyui_observer.dart:99
  void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) {}
                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

On Android the error above occurs only when you try to present the paywallView.
On iOs the app doesn't compile with the following error:

Swift Compiler Error (Xcode): Cannot find type 'AdaptyProductsFetchPolicy' in scope
/Users/davide.quadrelli/.pub-cache/hosted/pub.dev/adapty_ui_flutter-1.1.0/ios/Classes/Adapty+Encoding.swift:41:10

Swift Compiler Error (Xcode): Cannot find type 'AdaptyProductsFetchPolicy' in scope
/Users/davide.quadrelli/.pub-cache/hosted/pub.dev/adapty_ui_flutter-1.1.0/ios/Classes/AdaptyUI+Delegate.swift:118:69

My flutter doctor output is the following

[✓] Flutter (Channel stable, 3.13.2, on macOS 13.5 22G74 darwin-arm64, locale it-IT)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Android Studio (version 2022.3)
[✓] IntelliJ IDEA Community Edition (version 2022.2.3)
[✓] VS Code (version 1.81.1)
[✓] Connected device (2 available)
[✓] Network resources

• No issues found!

Handle (Android) Change subscription with params "subscriptionUpdateParams"

Hi, by using AdatyUI on Flutter App we cannot handle change subscription on Android. It's not possible to pass the current subscription data if user makes purchase when already has another subscription activated. Adapty SDK supports the Android change subscription by passing "subscriptionUpdateParams" due to the fact that play store does not automatically handle changes between different subscriptions. Is it planned to implement this feature also into the AdaptyUI?

Thanks in advice.

Could not close paywall

Could not close paywall by click on X button in iOS.

Logs from xcode:

[Adapty v2.7.0] - VERBOSE: Completed getProfile(_:) [d4rm9Z]  is successful.
[Adapty v2.7.0] - VERBOSE: LifecycleManager: syncProfile Done
[Adapty v2.7.0] - VERBOSE: LifecycleManager: scheduleProfileUpdate after 60.0 sec.
nw_resolver_start_query_timer_block_invoke [C30.1] Query fired: did not receive all answers in time for api.adapty.io:443
  adapty_flutter:
    version: "2.7.0"
  adapty_ui_flutter:
    version: "2.0.3"

iOS version 17.1

adapty and adapty ui version conflicts

[!] CocoaPods could not find compatible versions for pod "Adapty":
In Podfile:
adapty_flutter (from .symlinks/plugins/adapty_flutter/ios) was resolved to 2.9.0, which depends on
Adapty (= 2.9.1)

adapty_ui_flutter (from `.symlinks/plugins/adapty_ui_flutter/ios`) was resolved to 2.0.2, which depends on
  AdaptyUI (= 2.0.2) was resolved to 2.0.2, which depends on
    Adapty (~> 2.7.0)

Crash on view.present()

When I call

    final view = await AdaptyUI().createPaywallView(paywall: myPaywall, locale: 'en_US');
    await view.present();

I've get the crash

E/AndroidRuntime(11544): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.testgames.psyhologytests/com.adapty.internal.crossplatform.ui.AdaptyUiActivity}: com.google.gson.JsonIOException: Abstract classes can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type. Class name: com.adapty.models.AdaptyViewConfiguration$Asset
E/AndroidRuntime(11544): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4035)
E/AndroidRuntime(11544): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4201)
E/AndroidRuntime(11544): 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
E/AndroidRuntime(11544): 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
E/AndroidRuntime(11544): 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
E/AndroidRuntime(11544): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2438)
E/AndroidRuntime(11544): 	at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime(11544): 	at android.os.Looper.loopOnce(Looper.java:226)
E/AndroidRuntime(11544): 	at android.os.Looper.loop(Looper.java:313)
E/AndroidRuntime(11544): 	at android.app.ActivityThread.main(ActivityThread.java:8663)
E/AndroidRuntime(11544): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(11544): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
E/AndroidRuntime(11544): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
E/AndroidRuntime(11544): Caused by: com.google.gson.JsonIOException: Abstract classes can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type. Class name: com.adapty.models.AdaptyViewConfiguration$Asset
E/AndroidRuntime(11544): 	at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:136)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.createAccumulator(ReflectiveTypeAdapterFactory.java:425)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:381)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:144)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:431)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:391)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:431)
E/AndroidRuntime(11544): 	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:391)
E/AndroidRuntime(11544): 	at com.google.gson.Gson.fromJson(Gson.java:1214)
E/AndroidRuntime(11544): 	at com.google.gson.Gson.fromJson(Gson.java:1124)
E/AndroidRuntime(11544): 	at com.google.gson.Gson.fromJson(Gson.java:1034)
E/AndroidRuntime(11544): 	at com.google.gson.Gson.fromJson(Gson.java:969)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.SerializationHelper.fromJson(SerializationHelper.kt:67)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.CrossplatformHelper.fromJson(CrossplatformHelper.kt:33)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.ui.PaywallUiManager.getPersistedData(PaywallUiManager.kt:86)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.ui.PaywallUiManager.getData(PaywallUiManager.kt:18)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.ui.PaywallUiManager.setCurrentView(PaywallUiManager.kt:68)
E/AndroidRuntime(11544): 	at com.adapty.internal.crossplatform.ui.AdaptyUiActivity.onCreate(AdaptyUiActivity.kt:39)
E/AndroidRuntime(11544): 	at android.app.Activity.performCreate(Activity.java:8290)
E/AndroidRuntime(11544): 	at android.app.Activity.performCreate(Activity.java:8270)
E/AndroidRuntime(11544): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
E/AndroidRuntime(11544): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4009)
E/AndroidRuntime(11544): 	... 12 more

It is reproduces for adapty_ui_flutter: 2.0.1 and adapty_ui_flutter: 2.0.2 (did not check for earlier versions)

Issue while Handling Events on Android

Hey 👋

I have a Flutter app that I use adapty_ui_flutter. I created a custom event handler for the paywall view. Events are working as it is on iOS but everything seems buggy in Android.

I'm calling the paywall view like this:

showAdaptyPaywall() async {
   final AdaptyPaywall paywall = await Adapty().getPaywall(id: myID);
   final view = await AdaptyUI().createPaywallView(paywall: paywall, locale: 'en');
   await view.present();
   AdaptyUI().addObserver(MyCustomAdaptyObserver());
}

MyCustomAdaptyObserver

import 'dart:developer';
import 'package:adapty_flutter/adapty_flutter.dart';
import 'package:adapty_ui_flutter/adapty_ui_flutter.dart';
import 'package:url_launcher/url_launcher.dart';

class MyCustomAdaptyObserver implements AdaptyUIObserver {
  @override
  void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) async {
    log('paywallViewPerformedAction'); // This is not showing in the console. So, I'm assuming this is not even called?
    switch (action.type) {
      case AdaptyUIActionType.close:
        log('Close button pressed');
        await view.dismiss();
        break;
      case AdaptyUIActionType.androidSystemBack:
        log('Android back button pressed');
        await view.dismiss();
        break;
      case AdaptyUIActionType.openUrl:
        log('Opening URL: ${action.value}');
        if (action.value != null) openURL(Uri.parse(action.value!));
        break;
      case AdaptyUIActionType.custom:
        log('custom: ${action.value}');
        break;
    }
  }

  @override
  void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product) {
    log('paywallViewDidSelectProduct');
  }

  @override
  void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product) {
    log('paywallViewDidStartPurchase');
  }

  @override
  void paywallViewDidCancelPurchase(AdaptyUIView view, AdaptyPaywallProduct product) {
    log('paywallViewDidCancelPurchase');
  }

  @override
  void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile) {
    log('paywallViewDidFinishPurchase');

    if (profile.accessLevels['premium']?.isActive ?? false) {
      log('PURCHASE SUCCESSFUL. ${product.localizedTitle} is now active.');
    } else {
      log('PURCHASE FAILED');
    }

    view.dismiss();
  }

  @override
  void paywallViewDidFailPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error) {
    log('paywallViewDidFailPurchase');
  }

  @override
  void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile) {
    log('paywallViewDidFinishRestore');
  }

  @override
  void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) {
    log('paywallViewDidFailRestore');
  }

  @override
  void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error) {
    log('paywallViewDidFailRendering');
  }

  @override
  void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyError error) {
    log('paywallViewDidFailLoadingProducts');
  }

  Future<void> openURL(url) async {
    if (!await launchUrl(url)) {
      throw Exception('Could not launch $url');
    }
  }
}

view.dismiss(); is not working on Android. If I use Android's back button, paywall is closing but I can not open anymore in the app.
I'm getting this error typically:

I/flutter ( 7517): [AdaptyFlutter v2.7.1] - VERBOSE: [UI v2.0.5] <-- AdaptyUI.present_view() Adapty Error (code: 3001, message: AdaptyUIError.viewAlreadyPresented(093e7cc6-c6a3-4883-abac-f3a87b45b75a), detail: null)

Documents are not providing any further information about Flutter. So, what am I missing here?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.