I've just finished working on a personal app that has in-app purchases (Non-consumable). Unbelievably, the IAP part took me a lot of time due to a lack of documentation and complex testing process.
I am using the following package:
https://pub.dev/packages/in_app_purchase
Problem:
If you reopen the app on IOS, the app doesn't initialize the purchases until you click the button to buy again. However, it works perfectly on Android.
Future<void> initializeIap() async {
iapAvailable = await _iap.isAvailable();
if (iapAvailable) {
await _getProducts();
await _getPastPurchases();
_subscription = _iap.purchaseUpdatedStream.listen((data) {
_purchases.addAll(data);
_verifyPurchase();
});
_verifyPurchase();
}
}
Future<void> _getPastPurchases() async {
QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases();
//TODO: IOS Complete Purchases
for (PurchaseDetails purchase in response.pastPurchases) {
if (Platform.isIOS) {
InAppPurchaseConnection.instance.completePurchase(purchase);
}
}
_purchases = response.pastPurchases;
}
TIP:
Don't use
PurchaseStatus status; to validate the state of the purchase.
Related
I create a background fecth with workmanager flutter and following as the instruction on their documentation [here]https://github.com/fluttercommunity/flutter_workmanager/blob/main/IOS_SETUP.md. On android is working properly, but I am not sure with ios.
I add this on my main.dart
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) {
switch (task) {
case Workmanager.iOSBackgroundTask:
stderr.writeln("The iOS background fetch was triggered");
break;
}
bool success = true;
return Future.value(success);
});
}
and call it on here
void main() async {
.....
//workmanager
if (Platform.isIOS) {
Workmanager().initialize(
callbackDispatcher, // The top level function, aka callbackDispatcher
isInDebugMode:
true // If enabled it will post a notification whenever the task is running. Handy for debugging tasks
);
}
}
and I tested via simulator and simulate background fecth. And its print
The iOS background fetch was triggered
SwiftWorkmanagerPlugin - ThumbnailGenerator createThumbnail(with:) something went wrong creating a thumbnail for local debug notification
but the notification didn't appear as on the documentation did. Is my workmanager working?
Logically, I think is work, but im not sure. Also, it will running on background (even the apps is close/kill/terminated) every 15 minutes in iOS?
I want to handle foreground firebase messages.
But messaging().onMessage is not triggered very first time app launched in iOS. This is working fine in Android.
Exact scenario is:
First time launch app : messaging().onMessage not triggered in iOS
Close and reopen app : messaging().onMessage will trigger
import { Alert } from 'react-native';
import messaging from '#react-native-firebase/messaging';
function FCMReadInForeGround() {
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}, []);
}
export default FCMReadInForeGround;```
i hope this help you. i have same problem, and the im looking documentation ios messaging setup.
here the link : https://rnfirebase.io/messaging/usage/ios-setup .
in my case I haven't Linking APNs with FCM (iOS)
Try calling setBackgroundMessageHandler outside your component.
// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
try {
console.log('Remote notification', remoteMessage)
} catch (err) { console.log(err) }
});
Which is the best/simplest option to add app rating on a Xamarin.Forms application, the default stars form directly connected to the Play Store or App Store?
Edit: I've created an nuget package for this, you can download from Here or check the GitHub repo.
On Android you must open the PlayStore in order to rate the app, on iOS you can do it inside the app, but only from iOS 10 onwards.
You must implement native methods and use it via dependecy service.
Interface
public interface IAppRating
{
void RateApp();
}
Android
public class AppRatiing : IAppRating
{
public void RateApp()
{
var activity = Android.App.Application.Context;
var url = $"market://details?id={(activity as Context)?.PackageName}";
try
{
activity.PackageManager.GetPackageInfo("com.android.vending", PackageInfoFlags.Activities);
Intent intent = new Intent(Intent.ActionView, Uri.Parse(url));
activity.StartActivity(intent);
}
catch (PackageManager.NameNotFoundException ex)
{
// this won't happen. But catching just in case the user has downloaded the app without having Google Play installed.
Console.WriteLine(ex.Message);
}
catch (ActivityNotFoundException)
{
// if Google Play fails to load, open the App link on the browser
var playStoreUrl = "https://play.google.com/store/apps/details?id=com.yourapplicationpackagename"; //Add here the url of your application on the store
var browserIntent = new Intent(Intent.ActionView, Uri.Parse(playStoreUrl));
browserIntent.AddFlags(ActivityFlags.NewTask | ActivityFlags.ResetTaskIfNeeded);
activity.StartActivity(browserIntent);
}
}
}
iOS
public class AppRating : IAppRating
{
public void RateApp()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 3))
SKStoreReviewController.RequestReview();
else
{
var storeUrl = "itms-apps://itunes.apple.com/app/YourAppId";
var url = storeUrl + "?action=write-review";
try
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(url));
}
catch(Exception ex)
{
// Here you could show an alert to the user telling that App Store was unable to launch
Console.WriteLine(ex.Message);
}
}
}
}
On Android (tested in 9.0) I have to add this flag at FabriBertani´s solution:
activity.StartActivity(intent);
The Store Review Nuget plugin has been updated to v3 recently thanks to the new (August 2020) Android native Play Core library so that it displays an In-App Review on both iOS & Android using just one line of code:
await CrossStoreReview.Current.RequestReview(false);
So now, you don't have to worry about opening the url of the app in the external store or a web view, it will be shown directly in the app. You can see more details on this Microsoft Blog
Just remember to add the necessary code in the proguard file mentioned in the README of the Nuget's GitHub repository
What's the de-facto way to implement Facebook login with React Native? I'm looking for a way that Apple accepts (doesn't get rejected).
Apparently react-native-fbsdk doesn't use SFSafariViewController (it just opens a safari webview) and this isn't acceptable by Apple... they've rejected my app because of this.
My current code. Opens Safari webview.
LoginManager.setLoginBehavior('browser')
class FBLogin extends Component {
handleFacebookLogin = async () => {
try {
const result = await LoginManager.logInWithReadPermissions([
'public_profile',
'email',
'user_friends',
])
if (result.isCancelled) {
alert('Login cancelled')
} else {
const token = await AccessToken.getCurrentAccessToken()
this.props.login(token)
}
} catch (error) {
alert(`login error: ${error}`)
}
}
render() {
return (
<LoginButton
type={'primary'}
block
onPress={() => this.handleFacebookLogin()}
>
Login with Facebook
</LoginButton>
)
}
}
Rejected by Apple due to
We noticed that the user is taken to Safari to sign in or register for an account, which provides a poor user experience.
You can try using "react-native-app-auth" library. It has implemented SFAuthenticationSession with SFSafariViewController (Apple way of authenticating users for iOS 11 & up).
They have a pretty neat documentation: http://npm.taobao.org/package/react-native-app-auth
I created an app that uses in-app purchases, I already have set up the in-app purchases on iTunes and I even tested it using a sandbox user and all of this is working perfectly.
now that I included an iMessage app extension, the same in-app purchase products return invalidProduct Id, but continues working well inside the main app.
could be because the bundle id?
mainapp: com.whatever.bundleid
app iMessage: com.whatever.bundleid.iMessage
iMessage extension: com.whatever.bundleid.iMessage.MessagesExtension
btw, i'm using the SwiftyStoreKit pod.
if let inappIndentifier = stickerPackage.inAppPurchaseId {
SwiftyStoreKit.retrieveProductsInfo([inappIndentifier]) { result in
if let product = result.retrievedProducts.first {
let priceString = product.localizedPrice!
completion(true, priceString)
} else if let _ = result.invalidProductIDs.first {
completion(false, nil)
} else {
print("Error: \(result.error)")
completion(false, nil)
}
}
}
I made a huge mistake, instead of creating an iMessage extension, I've created an iMessage app extension.
Once I removed the "iMessage app" the in-app purchases started working correctly.