I am using revenucat to manage subscriptions in my app. But I noticed a problem. I have promo codes that I created on google play for my user. With this code, the user can use 3 months free of charge. When the user logs in on another device, I can't get the information that the user is in the trial period. Therefore, the purchase screen appears again. how can i solve this. I understand from the code below that the user is a premium member.
Future updatePurchaseStatus() async {
final purchaserInfo = await Purchases.getCustomerInfo();
final entitlements = purchaserInfo.entitlements.active.values.toList();
_entitlement =
entitlements.isEmpty ? Entitlement.free : Entitlement.premium;
if (entitlements.isNotEmpty) {
_entitlementInfo = purchaserInfo.entitlements.active.values.last;
}
notifyListeners();
}
Related
When I used Sandbox to test Flutter in_app_purchase in iOS, if I cancel a subscription in the Sandbox app store, it shows the subscription is already cancelled (but as the old subscription's expiration date is a year from now, so I assume the old one is still not expired), and then when I call InAppPurchase.instance.restorePurchases(), on the stream listen handler parameter List purchaseDetailsList, the canceled subscription still show up (and indeed show up multiple times, if I purchased and cancelled many times before). Is this the intended behaviour? How can I find out if a past purchase was already canceled but not expired yet? I am using in_app_purchase: ^3.0.6
If you are testing it in sandbox then the duration is lowered to minutes for testing.
Also to remove all purchases you can try this code
Future<void> clearTransactionsIos() async {
if (Platform.isIOS) {
final transactions = await SKPaymentQueueWrapper().transactions();
for (final transaction in transactions) {
try {
if (transaction.transactionState !=
SKPaymentTransactionStateWrapper.purchasing) {
await SKPaymentQueueWrapper().finishTransaction(transaction);
}
} catch (e) {
print(e);
}
}
}
}
This should remove all pending transactions.
More about IAP testing
https://help.apple.com/app-store-connect/#/dev7e89e149d
I am using cloud Firestore.
When I use cloud messaging to send push notifications to an app, a message goes to all users (users registered with Authentication) who are registered in the app.
The app has a login function, so I hope only the logged-in user gets notified.
That is, how can I send notifications only to specific users?
I want to set the time and day of the week with cloud messaging and send it to a specific device.
Now I even marked the token on the logcat and tested it in cloud messaging as shown in the picture.
However, the test cannot set the time and day of the week.
Is it possible to do this in the Fire Store? Or do I have to set the time and day of the week in the code as shown in the link?
enter image description here
//FirebaseMessagingService
#Override
public void onNewToken(String token) {
Log.e("NEW_TOKEN", token);
}
//MainActivity
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Log and toast
//String msg = getString(R.string.msg_token_fmt, token);
Log.d("NEW_TOKEN", token);
Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
}
});
I'll just write an answer just for better track.
As #Doug already mentioned, you could try using this code sample and try on your own.
Finally, is a good practice to show what you have tried and a code snippet to better understand your question.
I was trying to test sign-in to my home screen for my flutter app. I am using the google-signin ( https://pub.dev/packages/google_sign_in) package from Flutter to perform login and authentication. So once the login button is pressed, a popup appears asking the user to select the user account. At that point, I am unable to control the tap as this dialog screen is generated by the plugin. How do I implement selection of the user account in this case ?
test('Test Login', () async {
final Timeline timeline = await driver.traceAction(() async {
await driver.tap(find.byValueKey('GoogleLogin'));
await driver.tap(find.text('myemail#gmail.com')); // This will not work !!!
});
TimelineSummary.summarize(timeline)
..writeSummaryToFile('home_scroll_perf', pretty: true)
..writeTimelineToFile('home_scroll_perf', pretty: true);
});
In my opinion, this could be a problem when testing with any third party plugin. Please help.
It seems that the issue is still existing. There is no available workaround yet. Keep an eye on this GitHub post as this is closely monitored by the Flutter team.
Try Patrol, it lets you very easily interact with native UIs such as the Google sign-in dialog.
Below is a rough example of how I'd approach this. I'm going to assume that you're already signed in to a Google account, so the only thing you have to do is to select an email from the dialog.
// integration_test/sign_in_test.dart
void main() {
patrolTest(
'signs in with Google',
nativeAutomation: true,
(PatrolTester $) async {
await $.pumpWidgeAndSettle(YourAppWidget());
await $('Sign in with Google').tap();
await $.native.tap(Selector(text: 'your.email#gmail.com'));
await $.pumpAndSettle();
// should be signed in now
},
);
}
Remember: that integration tests has to be run with patrol drive, not flutter test integration_test.
I've set up AdMob ads on my app and want to set up In-App Purchases so that people can pay to disable the ads if they want to. I looked around for some guides on how to do it but they are all for Consumables, none for Non-Consumables. Even the example code that comes with the in_app_purchase Flutter package is only about Consumables.
Can someone give me some guidance on how to set up the minimal code just to disable ads in Flutter? I managed to set it up a couple of years back in React Native for consumables and even with guides I remember it was a bit of a nightmare.
I have the In-App Purchase set up in Appstoreconnect already, I just want to know what the actual code needed is. I'm assuming that with just disabling ads the code would be shorter than with consumables.
In the in_app_purchase readme it gives this:
final ProductDetails productDetails = ... // Saved earlier from queryPastPurchases().
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
if (_isConsumable(productDetails)) {
InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
} else {
InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
}
My app has a 1 month autorenewal subscription. When the user clicks on a "Buy a subscription" button I am saving date of purchase to shared preferences.
Then, after 1 month, I need to check is this subscription is still valid.
So how can I implement it?
==== UPDATE from 11.03.2020
Hi, I can see this post still reading by people who looking for a method of how to work with subscription in Flutter.
During 2019 I made two apps with thousands installs where users can buy a renewable subscription on the 2 platforms.
Until February 2020 I used for this package from Flutter team https://pub.dev/packages/in_app_purchase, BUT - there is no way to get info about the user to unsubscribe in iOS. This is not the plugin issue, but the iOS approach for the process. We should implement our own backend for security reasons (by the way Google also recommends to do the same, but still left the way to check state directly from the app).
So, after some researches, I found guys who made backend and plugin and it is free until you have less than 10 000 USD revenue for the month.
https://www.revenuecat.com/
https://pub.dev/packages/purchases_flutter
I've implemented this plugin in my apps and it works like a charm. There is some good approaches that allow you to get a subscription state at any point in the app. I'm going to make an example and article, but not sure about the timing.
====
UPDATE from 15.07.2019. Just to save time. The answer below was given for an outdated plugin for payments. After that Flutter team made plugin
https://pub.dev/packages/in_app_purchase
and I recommend using it.
=====
The best way is to use a secure backend server for receiving Real-time Developer Notifications.
But, it is possible to check status directly in the application.
So, when user tries to get access to some paid functionality you can check whether his subscription is active or not. Below is the example:
Create somewhere the file with the class
import 'dart:io' show Platform;
import 'package:flutter/services.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'dart:async';
class SubcsriptionStatus {
static Future<bool> subscriptionStatus(
String sku,
[Duration duration = const Duration(days: 30),
Duration grace = const Duration(days: 0)]) async {
if (Platform.isIOS) {
var history = await FlutterInappPurchase.getPurchaseHistory();
for (var purchase in history) {
Duration difference =
DateTime.now().difference(purchase.transactionDate);
if (difference.inMinutes <= (duration + grace).inMinutes &&
purchase.productId == sku) return true;
}
return false;
} else if (Platform.isAndroid) {
var purchases = await FlutterInappPurchase.getAvailablePurchases();
for (var purchase in purchases) {
if (purchase.productId == sku) return true;
}
return false;
}
throw PlatformException(
code: Platform.operatingSystem, message: "platform not supported");
}
}
Import it where you need to check subscription status and use in Constructor. For example:
class _SubscriptionState extends State<Subscription> {
bool userSubscribed;
_SubscriptionState() {
SubcsriptionStatus.subscriptionStatus(iapId, const Duration(days: 30), const
Duration(days: 0)).then((val) => setState(() {
userSubscribed = val;
}));
}
}
In variable userSubscribed will be the state - true or false.
(Please note you have to add flutter_inapp_purchase to your project).
There's a few ways of doing this, but I would not do this on the mobile device.
On Device like you asked for
Install Flutter Cache Manager, on start set a cache key value 'Subscription' to true with maxAgeCacheObject: Duration (days: 30). On every start check if that key still exists in the cache. If it does then it's still valid otherwise it has expired.
Suggested solution using FirebaseFunction
I would suggest setting up a backend to manage all this. This is not a task for the mobile device. You can have a Cloud Function from firebase where you pass a unique device id and it'll return whether the subscription is still valid or not. A serverless function should work for that. Pseudo steps:
(On Device)When the app starts up generate a guid and make an http post request with your guid.
(Server)In your serverless function save the date the request is made to your db along with the uniqueId that you sent. If your id is already in the DB then check if it's expired (date added - current date) < 30days. Return true or false from the function. True if still valid, false if not valid.
(On Device) When you receive true from your function then save the generated id locally on disk and continue with what you want to do. If it's false then lock the user out or show the subscription that you want to take care of.
Yeah, as to the vulnerabilities, there is one way to take the issue of users changing their time manually just to deceive the app, the solution I thought of is letting the DateTime come from the server this way, whether users change the Date and Time or not you end up with the correct time frame. I hope this helps.
As to checking whether subscription has expired, just follow the step #awaik gave and in addition, you can make request to your api to store the dateTime when the subscription was purchased and when you expect the subscription to expire. I suggest you save the purchase date and expected date in your server rather than on user device as clearing the cache or data directory of the app will lead to loss of the saved data. Goodluck.