Unable to fetch IAP from App Store causing app to fail - swift

I am trying to implement in App Purchases in a simple app I am creating.
I have a model method that is supposed to get the products using the productID. However the products array shown below returns an empty array. This causes the app to crash when trying to purchase an in app purchase.
I have followed a modified version of a tutorial I found online. But have not been able to figure out why mine doesn't work.
The Github repository for the project can be found here.
class Model {
var products = [SKProduct]()
func getProduct(containing keyword: String) -> SKProduct? {
print("The array of SKProducts in Model getProduct is \(products)")
let test = products.filter { $0.productIdentifier.contains(keyword) }.first
print(test)
return test
}
}

Related

Voice Catalog only has one package id:206

I am running into a similar issue as described here: https://github.com/heremaps/here-ios-sdk-examples/issues/165
I used to have access to multiple voice packages however since I had to change my appId and key, I only have one voice package in the catalog. Below code was working until I had to change key. The user in the github issue had to contact here customer support to enable it.
let voiceCatalog = NMAVoiceCatalog.sharedInstance()
voiceCatalog?.delegate
// gets the list of packages
voiceCatalog?.update()
let spanishVoice = voiceCatalog?.voicePackage(withId: 204)
let englishVoice = voiceCatalog?.voicePackage(withId: 206)
// Since the spanish voice catalog does not exist anymore, this will crash the app.
print("check for spanish voice--", voiceCatalog?.installedVoicePackages.contains(spanishVoice!))
if(voiceCatalog?.installedVoicePackages.contains(spanishVoice!) == false){
print("do installation here")
voiceCatalog?.installVoicePackage(spanishVoice!)
}

PKPassLibrary not returning passes

I have added Debit Card programmatically to Apple Wallet using swift code.
I need to show card status as provisioned so that user can should not try to add this card again.
for that I am using below code to get passes from wallet
let passLibrary = PKPassLibrary()
let devicePaymentPasses = passLibrary.passes().compactMap { $0.paymentPass }
let remotePaymentPasses = passLibrary.remotePaymentPasses()
both devicePaymentPasses and remotePaymentPasses are empty. please help.
You need to add the Wallet entitlement to the app, in order to read passes created with the app's team ID.

In App Purchase on Mac Catalyst Not Working

In app purchases work fine for my iOS side of things. The data from StoreKit is populated as it should. The same code doesn't work on the Mac Catalyst version of the project. I have even created a listing for my Mac app on App Store connect with different bundle identifiers for the in app purchases. I have a print function that returns what product StoreKit found, it works well on iOS, but results with nothing when using Mac Catalyst.
Here is what I have done:
Make sure that In App purchases has been added in the capabilities section.
Make sure the Store Kit framework has been imported.
Make sure the bundle identifiers are correct.
Make sure all agreements are filled out.
I am signed out of the Mac App Store.
Code that works on iOS but not on MacOS:
override func viewDidLoad() {
SKPaymentQueue.default().add(self)
let productIds: Set<String> = ["..."]
var request = SKProductsRequest(productIdentifiers: productIds)
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Loaded")
for product in response.products {
print("What came: \(product.productIdentifier) \(product.localizedTitle) \(product.price.floatValue)")}
The iOS app will return with the Product Identifier, Title and Price. The Mac app will return with nothing at all.
I found the problem. I had not created a strong reference to my product request.
This line of code fixed my issue:
var request: SKProductsRequest!

Firebase Cloud Functions will not fire from iOS app

I'm building an iOS app using Firebase for the backend and need to use Firebase Callable Cloud Functions. I have everything set up as per docs and functions fire and behave as expected when launched from browser or curl but I cannot get them to fire from my app.
I've set up a test app just using the functions and I cannot get that to fire from iOS app either. Not even a basic hello world. Nothing is getting through.
All of the following has been done:
Firebase side:
Firebase is connected to app successfully
Installed/Initialised the Firebase Functions locally.
Written function code in VSCode trying both Javascript and TypeScript
Successfully deployed to Firebase and can see function in console
Tested function via command line and browser on local server all works as expected
iOS side:
Pod installed Firebase functions
imported Firebase functions into ViewController
Used Firebase SDK to invoke function matching name of function on Firebase - attached to button trigger
And I get nothing... the print statement on the button works but the function doesn't fire and nothing gets logged to Firebase logs.
What am I missing or doing wrong here?
Tried new project with new instance of Firebase.
Copied code directly from examples on Firebase docs and followed everything step by step
FIREBASE CODE
const functions = require('firebase-functions');
const admin = require('firebase-admin')
exports.helloWorld = functions.https.onCall((data, context) => {
const text = data.text;
console.log("Text: " + text);
const uid = context.uid;
console.log("UID: " + uid);
const name = context.name;
console.log("Name: " + name);
console.log('Hello world fucking worked baby!');
return {
message: text
}
});
SWIFT CODE
import UIKit
import FirebaseFunctions
class ViewController: UIViewController {
lazy var functions = Functions.functions()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func fireFunction(_ sender: Any) {
print("Button Fire")
let data = ["text": "hello!"]
functions.httpsCallable("helloWorld").call(data) { (result, error) in
print("Function returned")
if let err = error {
print(err)
}
if let res = result {
print(res)
}
}
}
}
It seems that the Google Cloud Function is working properly if it is being called from a browser. You can also view the LOGs of the Cloud Function. Simply go to the Cloud Functions page and click on your function. Click on the VIEW LOGS button and try calling the URL again, if there is an error with the way Swift calls it, it will be logged there.
I have not worked with iOS Swift very much, but since you are trying to call the function via internet, I am thinking that you might need to give permissions to the App to access the Internet. It looks like the call is never initiated in the Cloud Function, that is why it is not triggered.
I assume that the Cloud Function is an HTTP triggered one. Therefore as a workaround, you can call the function initiating an HTTP request from the App. Again, this won't work though, unless you make sure that your App has the permissions to use the internet.

Is the SKStoreReviewController API also available for MacOS, and if yes, how to implement it?

I am using the SKStoreReviewController API in my iOS app to get reviews of my app. I also wanted to implement this into my MacOS app, but it seems that this is not possible. I imported StoreKit, but it says "Use of unresolved identifier 'SKStoreReviewController'". Do I need to implement this differently, or is this not meant to be used for the Mac Appstore?
As Marek pointed out, the SKStoreReviewController class is available since macOS 10.14+.
Use the requestReview() method to indicate when it makes sense within the logic of your app to ask the user for ratings and reviews within your app.
Apple still recommends in the Human Interface Guidelines to don't use buttons or other controls to request feedback and trigger, but trigger it only in other situations.
Apple has a nice example code to handle the review showing only for specific actions:
// If the count has not yet been stored, this will return 0
var count = UserDefaults.standard.integer(forKey: UserDefaultsKeys.processCompletedCountKey)
count += 1
UserDefaults.standard.set(count, forKey: UserDefaultsKeys.processCompletedCountKey)
print("Process completed \(count) time(s)")
// Get the current bundle version for the app
let infoDictionaryKey = kCFBundleVersionKey as String
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: infoDictionaryKey) as? String
else { fatalError("Expected to find a bundle version in the info dictionary") }
let lastVersionPromptedForReview = UserDefaults.standard.string(forKey: UserDefaultsKeys.lastVersionPromptedForReviewKey)
// Has the process been completed several times and the user has not already been prompted for this version?
if count >= 4 && currentVersion != lastVersionPromptedForReview {
let twoSecondsFromNow = DispatchTime.now() + 2.0
DispatchQueue.main.asyncAfter(deadline: twoSecondsFromNow, execute: {
SKStoreReviewController.requestReview()
UserDefaults.standard.set(currentVersion, forKey: UserDefaultsKeys.lastVersionPromptedForReviewKey)
})
}
Even though when I only call SKStoreReviewController.requestReview() there's no review prompt appearing. Does anyone know a a specific trick for macOS?
Edit: I've submitted an update to the app store and the review prompt is working! I don't know why it's not appearing when testing, but in production it seems to work!
SKStoreReviewController is for iOS only as seen in the "SDK" section of the
Documentation.
To let users write reviews, you will have to use the link to the Mac App Store.
let appid = 9999999999 // put your app id here
if let url = URL(string: "https://itunes.apple.com/us/app/id\?(appid)ls=1&mt=8&action=write-review") {
NSWorkspace.shared().open(url)
}
SKStoreReviewController is available even on macOS 10.14+, but sometimes i wasn't able to make it work with SKStoreReviewController.requestReview() so I use the manual mode that you can find here:
let appId = 1547575778 //Your app Id from the Itunes Connect portal
if let url = URL(string: "https://apps.apple.com/app/id\(appId)?action=write-review") {
NSWorkspace.shared.open(url)
}
SKStoreReviewController is available since macOS 10.14
You can use my tiny wrapper:
// Review after 3 launches
AppReview.requestIf(launches: 3)
// Review after 5 days
AppReview.requestIf(days: 5)
// Review after 3 launches and 5 days
AppReview.requestIf(launches: 3, days: 5)
https://github.com/mezhevikin/AppReview