multiple INApp purchase request for different product in tableView - swift

multiple in app purchaseI am working a music player application, the user need to purchase the albums before they start hearing it, I have attached a sample purchase screen. when the user tap it it should move to inApp purchase . The purchase type is non- consumable they need to pay only once.
I am having a table view with list of albums in it, if I purchase the first index album, it is working fine when I move to second index it was stating like already purchased.
I have used SwiftyStoreKit pod for the inappropriate purchase and everything is working as I expected. but I don't know how to handle tableview with n number of cell.
//INAPP purchase swift guy
func getinfo (purchase: RegisterPurchase) {
NetworkActivityIndicatioManager.NetworkoperationStarted()
SwiftyStoreKit.retrieveProductsInfo([bundleId + "." + purchase.rawValue]) { (result) in
NetworkActivityIndicatioManager.NetworkOperationFinished()
self.showAlert(self.alertForProductRetrievalInfo(result))
}
}
func purchase(purchase: RegisterPurchase) {
NetworkActivityIndicatioManager.NetworkoperationStarted()
SwiftyStoreKit.purchaseProduct(bundleId + "." + purchase.rawValue, atomically: true) { result in
NetworkActivityIndicatioManager.NetworkOperationFinished()
if case .success(let purchase) = result {
let downloads = purchase.transaction.downloads
if !downloads.isEmpty {
SwiftyStoreKit.start(downloads)
}
// Deliver content from server, then:
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
}
if let alert = self.alertForPurchaseResult(result) {
self.showAlert(alert)
}
}
}

Issue is with your product type. If you want to make the product purchasable again, you should use consumable purchase, NOT non-consumable.
Non-consumable product can be purchased only once for an iTunes
account.
For your case, you can change the product type to consumable, then save this purchase in server and link with the user. This way, you can unlock the album if user purchased before.

Related

How to request App Ratings with requestReview() correctly

I am currently learning how to ask the user for an AppStore rating in the app. I have read through numerous documentations and reports from Apple and other bloggers, but I still have questions:
I thought that I want to display my request after the user has completed a sequence of actions 3 times. But if the user doesn't want to rate my app right now, can I ask him to rate my app again later? I also read that Apple controls when and how often the review request is displayed (up to 3x / year)
My app has different functions. Therefore it is not guaranteed that the user accesses exactly this function, where I want to show the rating view. Is it therefore possible to call up the rating request at different points in the app and simply leave it up to Apple whether the rating request is also displayed?
Best regards
Edit for #K bakalov :
enum AppReviewRequest {
#AppStorage("runCountSinceLastRequest") static var runCountSinceLastRequest = 0
#AppStorage("lastVersion") static var lastVersion = ""
static let threshold = 4
static let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String
static func countUpRequestReview() {
if currentVersion != lastVersion {
if runCountSinceLastRequest < threshold - 1 {
runCountSinceLastRequest += 1
print(runCountSinceLastRequest)
}
}
}
static func requestReviewIfNeeded() {
if currentVersion != lastVersion {
if runCountSinceLastRequest == threshold {
if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
SKStoreReviewController.requestReview(in: scene)
lastVersion = currentVersion
runCountSinceLastRequest = 0
}
}
}
}
}
I assume you already read that but if you haven't I am leaving a link for you to check it out: https://developer.apple.com/documentation/storekit/requesting_app_store_reviews
It contains helpful information and guides when and how to prompt the user to leave a review.
Back to your questions.
Yes, you can ask again for review but there is no guarantee that the Review pop-up (alert) will be presented again. It is usually delayed in time and sometimes requires a new update of the app to trigger a new review prompt; That is correct, Apple has control over it but I don't know if its limited to only 3 times a year.
Yes, you can call it as many times as you want and wherever you find it suitable. Although, I highly encourage you to read (if still haven't) the link above. You need to think of a non-intrusive way to ask for review, otherwise you risk the user to dismiss the prompt, even if they like the app.
Just an advice, many apps use an approach with a custom popup "Do you like the app? Yes/No", if "Yes" then request a review using requestReview() call. And/or as mentioned in the article above, you can always use a manual review by redirecting to the AppStore, if you need it as a result of a CTA (tap on a button for example).

How to set local notification content to be the same as the content presented in the home screen when opened? [SWIFT]

I am trying to recreate an existing motivational quote app as practice.
On this app, you get a notification which displays the contents, and if you click it the home page provides you with the rest of the quote (screenshots below). I have seen this type of app a lot – they all use collection views and the notification and homepage content always match.
I have tried mimicking this by setting up local notifications for the next 7 days to provide the user with a random quote from my array:
func configureNotifications() {
let shuffled = quotes.shuffled()
for i in 1...7 {
let content = UNMutableNotificationContent()
content.title = “Daily quotes”
content.body = shuffled[i].text
let alertDate = Date().byAdding(days: i) // scheduled for next 7 days added
var alertComponents = Calendar.current.dateComponents([.day, .month, .year], from: alertDate)
alertComponents.hour = 10
Etc
}
func updateQuoteHome() {
guard let selectedQuote = quotes.randomElement() else {
fatalError("Unable to read a quote.")
}
updateLabels(with: selectedQuote)
}
However, once the notification is clicked, or if the user just randomly opens the app, the content displayed is obviously completely different.
What is the method to link these two together – is it even possible with local notification or are these apps utilising push notifications?
Is there something about this in the documentation?
Thank you ~
You should use Push Notifications for this feature. If you have little or no backend experience you can use Firebase Functions and Firebase Messaging to achieve this.

Testing iOS: Calling init() the first time an app is opened triggers 2 PURCHASE_CANCELLED events

The ios user account password pops up also. This doesn't happen if called again while app is still opened, but repeats if app is closed and reopened.
Thanks
Sounds like you have unfinished purchases that you need to finish.
Purchases will remain in a pending state until your application calls finish on them. This is to ensure that your application processes and verifies a purchase.
You should call InAppBilling.service.finishPurchase when you have process a purchase and either delivered the product or handled the cancellation/failure:
https://gist.github.com/marchbold/851359b9e456e1a85d65#file-distriqt-extension-inappbilling-makepurchase-as
private function purchase_cancelledHandler( event:PurchaseEvent ):void
{
// This transaction was cancelled so you should notify your user and finish the purchase
trace( "purchase cancelled" + event.errorCode );
if (event.data && event.data.length > 0)
InAppBilling.service.finishPurchase( event.data[0] );
}
At start up you can retrieve the pending purchases after the SETUP_SUCCESS event:
private function setupSuccessHandler( event:InAppBillingEvent ):void
{
var pending:Array = InAppBilling.service.getPendingPurchases();
// Iterate over and handle as required
}
http://docs.airnativeextensions.com/inappbilling/docs/com/distriqt/extension/inappbilling/InAppBilling.html#getPendingPurchases()

How to use prime31 in app billing plugin Unity android to add action on purchase

I have a big problem.
I got the plugin to work, and i can test purchase my items.
But i can`t find the place in the scripts where i can add the action to use when a item was purchased. i have 3 items, named "item60" "item70" and "item80".
Can anyone help me please ?
i use prime31 and i take care of the actions in this method, here is my remove ads purchase
void purchaseSucceededEvent( GooglePurchase purchase )
{
Debug.Log( "purchaseSucceededEvent: " + purchase );
if(purchase.purchaseState == GooglePurchase.GooglePurchaseState.Purchased){
if(purchase.productId == "jacs.apps.adds")
{
Debug.Log("inside jacs.apps.adds");
if(PlayerPrefs.HasKey("plus"))
{
adds = false;
PlayerPrefs.SetString("addskey","true");
}else{
PlayerPrefs.SetString("plus","on");
adds = false;
PlayerPrefs.SetString("addskey","true");
}
GoogleIAB.consumeProduct( "jacs.apps.adds" );
}
}
}

Titanium_iphone contacts

I am trying to list contacts with Titanium. WOrks on android device, but on iphone simulator doesn't return anything.
var contacts= Ti.Contacts.getAllPeople();
alert("contacts.length");
returns 0. I am not sure what am i missing here.
Make sure that you have contacts created on your iOS simulator:
Use Home button (CMD+Shift+H) to go to dashboard.
Open up Contacts app
Create few contacts which you want to retrieve in your app.
Also before you call Ti.Contacts.getAllPeople() you have to request authorisation to contact list. Try code below:
function processContacts() {
Ti.API.info('authorized');
var contacts = Ti.Contacts.getAllPeople();
Ti.API.info(contacts.length);
}
if (Ti.Contacts.contactsAuthorization == Ti.Contacts.AUTHORIZATION_AUTHORIZED){
processContacts();
} else if (Ti.Contacts.contactsAuthorization == Ti.Contacts.AUTHORIZATION_UNKNOWN){
Ti.Contacts.requestAuthorization(function(e){
if (e.success) {
processContacts();
} else {
Ti.API.info('disallowed');
}
});
} else {
Ti.API.info('disallowed');
}
One last thing, in your code you wrote: alert("contacts.length") which will always display dialog view with "contacts.length" as a string, not value. To call it properly you should write: alert(contacts.length) without double quotes.