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

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

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!)
}

CloudKit CKShare URL Goes Nowhere

I have successfully saved a CKShare URL to CloudKit, and I can see that the user is INVITED in the CloudKit Dashboard. My Mac app emailed the URL to that person, but when they click it, all they see it this screen on icloud.com:
Clicking OK makes everything disappear so all you see is the background on the web page.
My understanding is that the URL is supposed to open my Mac app where it will fire userDidAcceptCloudKitShareWith in my app delegate. But it does nothing.
Could this be because my app is in development and not in the Mac App Store yet? Do I need a custom URL scheme to get it to open my app?
Documentation on this stuff is pretty sparse. I'd love any help someone can provide.
I have since learned that you must specify a fallback URL for your CloudKit container. In cases where the app isn't installed (or isn't recognized, which seems to be the case when doing dev builds in Xcode like I am), CloudKit will forward share URL to somewhere you specify. They append the unique share ID to the URL so that you can process it on your own web page.
In the CloudKit dashboard, go to Environment Settings... and you'll see this popup:
I have it redirect to https://myapp.com/share/?id= and on my web page where it redirects to, I do a $_GET['id'] to grab the id. I then do another redirect to my application using a custom URL scheme and pass the share ID (e.g. myapp://abc123 where abc123 is the share ID).
In my app delegate, I receive the URL like this:
func application(_ application: NSApplication, open urls: [URL]) {
if let url = urls.first, let shareId = url.host{
fetchShare(shareId) //<-- sharedId = abc123
}
}
I then use CKFetchShareMetadataOperation to look up the URL of the share and CKAcceptSharesOperation to accept it like this:
func fetchShare(shareId: String){
if let url = URL(string: "https://www.icloud.com/share/\(shareId)"){
let operation = CKFetchShareMetadataOperation(shareURLs: [url])
operation.perShareMetadataBlock = { url, metadata, error in
if let metadata = metadata{
//:::
acceptShare(metadata: metadata)
}
}
operation.fetchShareMetadataCompletionBlock = { error in
if let error = error{
print("fetch Share error: \(error)")
}
}
CKContainer.default().add(operation)
}
}
func acceptShare(metadata: CKShareMetadata){
let operation = CKAcceptSharesOperation(shareMetadatas: [metadata])
operation.acceptSharesCompletionBlock = { error in
if let error = error{
print("accept share error: \(error)")
}else{
//Share accepted!
}
}
CKContainer.default().add(operation)
}
I think there are easier ways to work through this using NSItemProvider and NSSharingService, but I'm doing a lot of custom UI and wanted to have full control of the share workflow.
I hope this helps someone. :)

How to start watchApp from iPhone

I am developing a watch app and I want the watch app to activate when I start the app on the iPhone, but I can't find out how to do that.
The question has been asked in a number of forums and the answer has always been "Not possible", but there must be another answer as there are plenty of apps that do open the watch app automatically: Maps, Podcasts to name but two.
So what's the secret?
Here is the code snippet. You are supposed to only use it for a workout app but on the watch side you don't really have to start HKWorkoutSession.
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.activityType = .traditionalStrengthTraining
workoutConfiguration.locationType = .indoor
if WCSession.isSupported(), WCSession.default().activationState == .activated , WCSession.default().isWatchAppInstalled{
healthStore.startWatchApp(with: workoutConfiguration, completion: { (success, error) in
print(error.debugDescription)
})
}

Add the Association Domains feature to your App Id?

I'm trying to implement Firebase Dynamic Linking.
i have created project on firebase console and provided the required
value(prefx and appid).
i also have allowed the association domains from developer console
and it is sucessfully showing true flag.
in xcode i have on the feature of association domain and added the url identifiers etc.
Problem: still the problem i'm facing is that Association Domain Section says
Add the Association Domains feature to your App ID.
don't know whats the reason why i'm getting this error.
The screen shot is also attached for prove.
i have figured this out by searching for long time.
This is basically not a big issues the error
“Add the associated Domains feature to your App ID”
Will go away once you enable the Associated Domains in your APP ID in developer.apple.com. If it doesn’t go away, quit and relaunch the xcode few times and it will work.
reference: https://medium.com/#abhimuralidharan/universal-links-in-ios-79c4ee038272
I had a similar problem. The problem was solved when I turned off and turned on the feature in Capabilities. But then I had several entitlements files in different folders. Steps to combine these files into one:
Open in text editor MY_PROJECT_NAME.xcodeproj\project.pbxproj
Find CODE_SIGN_ENTITLEMENTS and set correct path. Example:
"MY_PROJECT_NAME/Entitlements/MY_TARGET_NAME.entitlements"
I do not recommend using a standard text editor, since it can automatically replace some characters in the file while saving.
You need to add Associated domains to your App Capabilities. Please see screenshot. Add applinks:yourdomain.com
Then Use below code to get Short URL
guard let link = URL(string: "https://www.yourdomain.com/share_location.html?Id=\(RandomID)&uid=\(uid)") else { return }
let dynamicLinksDomain = "yourdomain.page.link"
let components = DynamicLinkComponents(link: link, domain: dynamicLinksDomain)
// [START shortLinkOptions]
let options = DynamicLinkComponentsOptions()
options.pathLength = .unguessable
components.options = options
// [END shortLinkOptions]
// [START shortenLink]
components.shorten { (shortURL, warnings, error) in
// Handle shortURL.
if let error = error {
print(error.localizedDescription)
return
}
print(shortURL?.absoluteString ?? "")
}

Sharing on WhatsApp in iOS 9.0

I m new in iOS development and i want to integrate WhatsApp sharing in my app in ios 9.0 . i have searched various methods but they all are depreciated in ios 9.0
Can anyone suggest me updated method for the same,
#IBAction func whattsappInvite(sender: UIButton)
{
let urlString = "Hello Friends, Sharing some data here... !"
let urlStringEncoded = urlString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
let url = NSURL(string: "whatsapp://send?text=\(urlStringEncoded!)")
if UIApplication.sharedApplication().canOpenURL(url!) {
UIApplication.sharedApplication().openURL(url!)
}
}
Apple changed the canOpenURL method on iOS 9. Apps which are checking for URL Schemes have to declare these Schemes as it is submitted to Apple. Else canOpenURL returns false.
Add whatsapp field in LSApplicationQueriesSchemes in info.plist of your app.
Or try using whatsapp share extension
To share with Whatsapp, you can use your code or this one as a base :
var whatsappURL:NSURL?= NSURL(string: "whatsapp://send?text=Hello%2C%20World!")
if (UIApplication.sharedApplication().canOpenURL(whatsappURL)) {
UIApplication.sharedApplication().openURL(whatsappURL)
}
None of these methods are deprecated in iOS 9.0.