Different voices in Text to Speech iOS app - swift

I have a Text to Speech App and all is good, but I was looking for a voice.
In Settings/Accessibility/Voice Over/Speech/Voice there is a list of voices. I wanted to select one of those, for example "Susan (Enhanced)". How would I go about doing that?
I am new to Text to Speech and AVSpeechSynthesizer so I was hoping for some advice how to select that voice?
When I try it in General/Settings it sounds good, but when I select, what I thought was that voice it in my App, it sounds different. This happens with all of the voices I tried.
Here is the code I used to speak the text:
for voice in AVSpeechSynthesisVoice.speechVoices()
{
print("\(voice.name)")
if voice.name == "Susan (Enhanced)" {
self.voiceToUse = voice
}
}
let textToSpeak = self.tvTextToSpeak.text
if (!textToSpeak!.isEmpty)
{
let speechSynthesizer = AVSpeechSynthesizer()
let speechUtterance: AVSpeechUtterance = AVSpeechUtterance(string: textToSpeak!)
speechUtterance.voice = self.voiceToUse
speechSynthesizer.speak(speechUtterance)
}
So if I use the same text as the example in the iOS settings it sounds different in my App, why?
Is it something I need to do?
Are those voices special?
Does it have to do with the utterance, I have not set that.
Thanks for any clarification.

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).

Shortcut/Action on Siri Watch Face with independent WatchOS app

I'm relatively new to making apps, and even newer to independent watch apps. As training, I'm making a watch app that I can use to log my water intake throughout the day. I've created a new intent definition file (see image 1) on which I've checked the marks for all the target memberships (the app, the WatchKit app, and the WatchKit extension). Furthermore, the target membership class is a public intent for the WatchKit extension.
When logging my water I execute the following code:
let intent = INManager.intent(drink: item)
INManager.donateShortcuts(withIntent: intent)
and my IntentManager looks like this:
import Foundation
import Intents
class IntentManager {
func intent(drink: Drink) -> LogDrinkIntent {
let intent = LogDrinkIntent()
intent.uuid = drink.id.uuidString
intent.name = drink.name
intent.emoji = drink.emoji
return intent
}
func donateShortcuts(withIntent intent:INIntent) {
var relevantShortcuts: [INRelevantShortcut] = []
if let relevantShortcut = defaultRelevantShortcut(withIntent: intent) {
relevantShortcuts.append(relevantShortcut)
}
INRelevantShortcutStore.default.setRelevantShortcuts(relevantShortcuts) { (error) in
if let error = error {
print("Failed to set relevant shortcuts: \(error))")
} else {
print("Relevant shortcuts set.")
}
}
}
private func defaultRelevantShortcut(withIntent intent: INIntent) -> INRelevantShortcut? {
if let shortcut = INShortcut(intent: intent) {
let relevantShortcut = INRelevantShortcut(shortcut: shortcut)
relevantShortcut.shortcutRole = .action
let template = INDefaultCardTemplate(title: "Log Drink")
relevantShortcut.watchTemplate = template
print("Returning relevant shortcut.")
return relevantShortcut
}
return nil
}
}
When logging a drink the confirmation Returning relevant shortcut. and Relevant shortcuts set. are printed. However, the Siri watch face doesn't update to include a link to my action. I got the code for the IntentManager from this Medium article.
I really appreciate your time and help. I've had a hard time trying to find any details about this functionality and Apple's documentation is imo inferior. Thank you! If you need more details or such, feel free to ask.
Image 1
Let's saddle the horse from behind: Generally speaking, you want to make use of Soup Chef. Now you can categorize Siri suggestions into two sub-groups, being donated shortcuts and relevant shortcuts.
In your specific example of a "water intake" logging app, you should work with donating the INIntent to INIteraction. The reason for that is quite simple: Your suggestion is due to an action a user has committed within your application, not based upon plainly relevance, thus your passage about INRelevantShortcutStore isn't necessary and/or should be replaced with INInteraction.
To re-phrase myself: The issue is that you parse INRelevantShortcutStore as a donation, see here:
func donateShortcuts(withIntent intent:INIntent) {
var relevantShortcuts: [INRelevantShortcut] = []
if let relevantShortcut = defaultRelevantShortcut(withIntent: intent) {
relevantShortcuts.append(relevantShortcut)
}
INRelevantShortcutStore.default.setRelevantShortcuts(relevantShortcuts) { (error) in
if let error = error {
print("Failed to set relevant shortcuts: \(error))")
} else {
print("Relevant shortcuts set.")
}
}
}
... as explained above, that is not the correct usage for INIntent in your specific example.
I highly suggest to read through Soup Chef in general as well as specifically donating shortcuts to Siri (what you want to do!). The documentation is very detailed and explanative!

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.

Changing app language on the fly in iOS

I am new to iOS and I know this is a very frequently asked question, but I have found no appropriate answer for my query.
I have added text to controls on the app like this
let productDescriptionCell = tableView.dequeueReusableCellWithIdentifier("textDescriptionCell") as! TextDescriptionCell
productDescriptionCell.labelForCell.text = "Description"
productDescriptionCell.labelForCell.sizeToFit()
productDescriptionCell.labelForCell.adjustsFontSizeToFitWidth = true
like the 'Description' text above.
I want to have a button in my app, which lets the user change the language on the fly. I have found the following code as the most relevant but this requires an app restart.
userDefaults.setObject(["\(cc)"], forKey: "AppleLanguages")
userDefaults.synchronize()
In addition, I have text hard coded in my storyboard controllers, I want those localized as well. How can I achieve this?
Thai and English are the languages I need localization for
productTitleCell.textFieldForCell.placeholder = SpecProvider.spec.localizedTuv(createLocalizedString("en", tuvEnglish: "Enter Title", tuvThai: "ป้อนชื่อ"))
func localizedTuv(localizedString: LocalizedString) -> String {
var locale = LocaleSelectionService.sharedInstance.getCachedLocale()
if locale.isEmpty {
locale = ""
}
switch(locale) {
case "en": return localizedString.getTuvEnglish()
case "th": return localizedString.getTuvThai()
default: return localizedString.getTuvEnglish()
}
}
I have tried the above code, but this could get very tedious. Please help, I am really stuck!
You have to create string files, and add the labels for every language you want to support. Once this is done you can use NSLocalizedString for the text used in your ViewController.
Here's a tutorial http://www.raywenderlich.com/64401/internationalization-tutorial-for-ios-2014

AppleWatch Speech-to-Text functionality not working

I am trying to implement Speech-to-text feature for watchkit app.
I referred this question which has sample code.
Following is the code I tried:
self.presentTextInputControllerWithSuggestions(["Start it", "Stop it"], allowedInputMode: .Plain, completion: { (selectedAnswers) -> Void in
if selectedAnswers.count > 0 {
if let spokenReply = selectedAnswers[0] as? String {
self.label.setText("\(spokenReply)")
}
}
})
label is a label to display text I speak.
When I run it, it shows the screen where you are supposed to speak (Siri kind of screen) and you have two options on top: ‘Cancel', and ‘Done'. Once I am done speaking, I tap on ‘Done’ but screen doesn’t go away or shows me initial screen, I always have to tap on ‘Cancel’ to go back, and I don’t get any speech data in form of text. I checked it and seems like selectedAnswers is always an empty array, unless I tap on the "Start it"/"Stop it" options.
Can anyone help me with this? I want to show the spoken message on label. I have code inside awakeWithContext method in InterfaceController.swift file, am I supposed to put it somewhere else?
I am using iPhone with iOS 9 beta 2 and watchOS 2 beta on AppleWatch.
Thanks!
You can ask for user input and give him suggestion (see Swift example bellow).
self.presentTextInputControllerWithSuggestions(["suggestion 1", "suggestion 2"] allowedInputMode: .Plain, completion: { (answers) -> Void in
if answers && answers.count > 0 {
if let answer = answers[0] as? String {
println("\answer")
}
}
})
If suggestion is nil it goes directly to dictation. It is not working on the simulator but it is on real watch.
Your approach is correct but something is wrong with your SIRI , try changing the language.
It should work like these.