Voice Catalog only has one package id:206 - swift

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

Related

How to solve Swift FileManager couldn’t open file because of permission and implement file access

I made a music app for macOS that need the access of the file on disk. I can get the proper url, but I can't access the file. To figure out that problem, here I create a concise code snippet to concentrate on the question itself.
.onAppear {
var url = FileManager.default.homeDirectoryForCurrentUser
url.appendPathComponent("Downloads/Test.txt")
var text: String = ""
do {
text = try String(contentsOf: url)
} catch {
print("ERROR: \(error.localizedDescription)")
}
}
The output would be like this
ERROR: The file “Test.txt” couldn’t be opened because you don’t have permission to view it.. So I noticed App Sandbox in Targets > Signing & Capabilities. But at the list of file access (as you can see in the following picture), there's only User Selected File, Downloads Folder, Pictures Folder, Music Folder and Movie Folder. So I come up with 3 questions:
What that User Selected File means? Is that means that the user can select some specific file for my app to access? If it is, how can user selects them?
How can I get access to other folders like Desktop Folder if I remain the App Sandbox capability here?
I also noticed the trash icon on right-upper corner. If I delete App Sandbox, I can access every folder I want with the user's agreement by a default system pop-up. But what the deletion of App Sandbox means? Does it make my app "untrusted" somehow when user install it or others? Does it cause any security problems?
And It couldn't be better if you can tell me the conventions major developers follow when meet this problem. I would highly appreciate your help.

Firebase Offline Support: upload posts while user is offline and sync when user comes online in iOS Swift app

I am using firebase in an iOS-Swift project in which I have to enable offline support for uploading posts, in the post there is a picture and caption just like Instagram, so what I want is when user is offline and he/she wants to upload a post, his/her picture get saved in cache and when user comes online that photo get uploaded and give back a download url that we can use for saving posts-details it in database.
sample code is:
let photoIDString = UUID().uuidString
let storageRef = Storage.storage().reference(forURL: "storage ref URL").child("posts").child(photoIDString)
storageRef.putData(imageData, metadata: nil, completion: { (metadata, error) in
guard let metadata = metadata else {
return
}
if error != nil {
return
}
storageRef.downloadURL(completion: { ( url, error ) in
guard let downloadURL = url else {
return
}
let photoUrl = downloadURL.absoluteString
self.sendDataToDatabase(photoUrl: photoUrl)
})
}
)
I want to know what changes should I make in my code to provide the offline capability. Any code snippet will help more.
The problem is better view as re-send to server when there is an error.
For your offline case, you can check if the error return is a network error, or manually check network connection availability.
You can create a re-send array of object
e.g
var resendList : [YourObjectType]
// when failed to send to server
resendList.append(yourFailedObject)
And then, 2 solutions:
Check the network connectivity manually and reupload in when the app become active in func applicationDidBecomeActive(_ application: UIApplication) in appDelegate. For checking connectivity you can try the method here: Check for internet connection with Swift But this has a problem that, the user has to go out the app and back again with network connected
Keep track(listen to notification) on the connectivity change, using a suggestion method by https://stackoverflow.com/a/27310748/4919289 and reupload it to server
and loop through all objects in resendList and re-upload again.
I am not an iOS developer, but I can share logical flow and some references.
When user clicks on upload: Check if network is available?
if yes: upload the post.
if no:
save the post to app storage or offline database
set broadcast receiver to receive broadcast when device comes online. This link may be helpful.
upload post when device comes online.
If you are looking for solution that is offered by Firebase, you may find more details here.
Firebase offers you plenty of ways to do this in their documentation. https://firebase.google.com/docs/database/ios/offline-capabilities
When uploading to the firebase server, it will queue itself and wait until it has a internet connection again to upload. If this happens to timeout or you want to do it your own way just attempt to upload with a completionHandler on the setValue or updateChild functions - if not successfully and the error message is because of internet, add it to a local cache to the phone with the data and the path to the firebase server.
onLoad, attempt the same upload again until it succeeds, once it succeeds - clear the local cache.

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 ?? "")
}

App to open in Spanish when participant clicks on Spanish Website in iOS

I have a project and this project support two languages English and Spanish.
If the user has Spanish languages selected phone, the app opens Spanish. The same cycle works for English also.
Second, We have a website and this website provides Spanish and English support. User can register ( Sign Up ) or login (Sign In)
from English site or Spanish site.
My question, As a User if I choose to register via the Spanish site, I should be taken to the app in Spanish and not English.
How can I do this? Universal Link or Deep Link. Is there anyone build this cycle previously?
You cannot change the device's language from within an app.
A solution for your use case could be to manually handle localization in your project: instead of relying on NSLocalizedString you'd have to use your own function for providing the localization for a given string/key. In the "normal" usage scenario you'd use the preferred language of the system; when opening the app via a link you'd add the language as URL parameter and use that language for the app session. (Note that this will not work with Storyboard or Info.plist localizations, only with texts you explicitly set in code).
Use Branch iOS SDK for deep linking so that you can ensure that a user receives the language even when they don't have the app installed before hand. In your links you should be able to set a field language to english, epanish, etc. When ever a user opens your application you can just pull that information out of the Branch callback like so.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// listener for Branch Deep Link data
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// do stuff with deep link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
let language = params?['language']
//Store this in their NSUserDefaults
let defaults = UserDefaults.standard.set(language, forKey: "language")
}
return true
}
The information in your UserDefaults will persist until the user deletes the app and reinstalls it.
let language = UserDefaults.standard.string(forKey: 'language')

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