1

I can't find the cause of the error when setting up RevenueCat in my first application. Please help me find the cause of this error: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value

I think the error is in this block:

  PurchasesConfiguration configuration;
  print('2');
  configuration = PurchasesConfiguration(StoreConfig.instance!.apiKey)
    ..appUserID = null
    ..observerMode = false;

It gives the following error:

enter image description here

Here is my user verification screen file. Which should be shown before the main screen:

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  late Timer timer;

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

    timer = Timer(const Duration(seconds: 10), () {
      print('timer');
      goToMain();
    });

    print('start');
    SubscriptionsProvider.shared.addListener(() async {
      if (!mounted) {
        return;
      }
      // print(SubscriptionsProvider.shared.entitlementIsActive);

      if (SubscriptionsProvider.shared.entitlementIsActive) {
        goToMain();
      } else {
        print('else');
        try {
          SubscriptionsProvider.shared.subs =
              await Purchases.getProducts([sub1Id, sub2Id, sub3Id]);
        } on PlatformException catch (e) {
          print('error');
          goToMain();
        }

        if (SubscriptionsProvider.shared.subs == null ||
            SubscriptionsProvider.shared.subs!.isEmpty) {
          goToMain();
        } else {
          goToPayWall();
        }
      }
    });

    // initPlatformState();
  }

  goToMain() {
    if (mounted) {
      Navigator.of(context)
          .pushReplacement(MaterialPageRoute(builder: (context) => Mainpage()));
    }
  }

  goToPayWall() {
    if (mounted) {
      Navigator.of(context).pushReplacement(
          MaterialPageRoute(builder: (context) => PayWallRevenueCat()));
    }
  }

  @override
  void dispose() {
    timer.cancel();
    SubscriptionsProvider.shared.removeListener(() {});
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        decoration: const BoxDecoration(
            gradient: LinearGradient(
                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
                colors: [Color(0xff000000), Color(0xff004BA4)])),
        child:
            const Scaffold(body: Center(child: CircularProgressIndicator())));
  }
}

Additional file:

class SubscriptionsProvider extends ChangeNotifier {
  // var subActive = false;

  static SubscriptionsProvider shared = SubscriptionsProvider._();
  bool entitlementIsActive = false;
  String appUserID = '';

  List<StoreProduct>? subs;

  SubscriptionsProvider._() {
    initPlatformState();
  }

  initPlatformState() async {
    // Enable debug logs before calling `configure`.
    print('1');

      await Purchases.setLogLevel(LogLevel.debug);

      PurchasesConfiguration configuration;
      print('2');
      configuration = PurchasesConfiguration(StoreConfig.instance!.apiKey)
        ..appUserID = null
        ..observerMode = false;
        // ..usesStoreKit2IfAvailable = true;

      await Purchases.configure(configuration);
      print('3');
      appUserID = await Purchases.appUserID;
      print('4');
      Purchases.addCustomerInfoUpdateListener((customerInfo) async {
        print('Purchases.addCustomerInfoUpdateListener started');
        appUserID = await Purchases.appUserID;

        CustomerInfo customerInfo = await Purchases.getCustomerInfo();


        (customerInfo.entitlements.all[entitlementID] != null &&
            customerInfo.entitlements.all[entitlementID]!.isActive)
            ? entitlementIsActive = true
            : entitlementIsActive = false;
        notifyListeners();
      });
  }
}
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
skv500
  • 47
  • 6

3 Answers3

1

Based on the error message StoreConfig.instance is null. And while you use null-assert(!) on null value, it returns Null check operator used on a null value.

A better way of doing it checking null first.same way you did for ..all[entitlementID] != null

 final apiKey = StoreConfig.instance?.apiKey;
 if(apiKey==null){
   debugPrint("got null on api");
   return;
  }
 configuration = PurchasesConfiguration(apiKey)
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • This removed the error, but in my opinion it did not solve the problem. ` Performing hot restart... Syncing files to device sdk gphone x86... Restarted application in 3 341ms. I/flutter (17430): start I/flutter (17430): 1 I/flutter (17430): got null on api I/flutter (17430): timer ` Maybe a problem with apiKey? – skv500 Mar 14 '23 at 06:18
  • make sure to initialize the instance `StoreConfig` , depends on how you've defined it, it can be like `StoreConfig.init()` on top level, based on your `StoreConfig` – Md. Yeasin Sheikh Mar 14 '23 at 06:21
  • Added my StoreConfig file – skv500 Mar 14 '23 at 06:55
1

Here is my StoreConfig file:

class StoreConfig {
  final Store store;
  final String apiKey;
  static StoreConfig? _instance;

  factory StoreConfig({required Store store, required String apiKey}) {
    _instance ??= StoreConfig._internal(store, apiKey);
    return _instance!;
  }

  StoreConfig._internal(this.store, this.apiKey);

  static StoreConfig? get instance {
    return _instance;
  }

  static bool isForAppleStore() => _instance?.store == Store.appStore;

  static bool isForGooglePlay() => _instance?.store == Store.playStore;
}
skv500
  • 47
  • 6
0

Solved a problem. It was necessary to add this to the beginning of the application:

  if (defaultTargetPlatform == TargetPlatform.android) {
    StoreConfig(
      store: Store.playStore,
      apiKey: googleApiKey,
    );
  } else if (defaultTargetPlatform == TargetPlatform.iOS) {
    StoreConfig(
      store: Store.appStore,
      apiKey: appleApiKey,
    );
  }
skv500
  • 47
  • 6