I've integrated code from twilio voice quickstart https://github.com/twilio/voice-quickstart-swift and got my app working up to some extent.
I'm facing problem with "Voice Bot". I'm not sure what this is and how I can implement it in different way. This is for outgoing call. After call is completed, Voice Bot is triggered but it doesn't show on the top of my VC where I'm handling all outgoing call related stuff, it remains in the background and making any subsequent call fails. When I go back from VC to other VC then screen flickers and it seems Voice Bot shows sometimes and then flow completes.
I'm not sure what this Voice Bot is and how we can avoid it or redirect to be handled in a VC? All I can guess is that it's from Apple's Call kit if i'm not wrong.
Any help on how to make it work?
Update on comment: I've used cocoapods to install Twilio.
pod 'TwilioVoice', '~> 2.0'
Here is the code:
#IBAction func placeCall(_ sender: UIButton) {
if (self.call != nil && self.call?.state == .connected) {
performEndCallAction(uuid: self.call!.uuid)
self.toggleUIState(isEnabled: false, showCallControl: false)
} else {
let uuid = UUID()
let handle = "Voice Bot" // <==== ????
performStartCallAction(uuid: uuid, handle: handle)
}
}
It's the name which appears on callKit. You can change it to be the name of your app or caller name. Apart from this name it has no significance whatsoever. If you are using client-to-client call only then change it to be your app's name. If you are using your app for phone call as well then change it to be caller's name.
Related
I am trying to get a callback or notification if a user clicked on a "call" or "cancel" button when trying to call a phone number from the app. I use the following code:
guard let url = URL(string: "tel://\(number)") else { return }
UIApplication.shared.open(url, options: [:]) { didCall in
print(didCall)
}
Issue with this callback is that it is triggered when the dialog appears not when I click any of the buttons and it is always true. I couldn't find another solution. I know that since iOS 10 there's a notification I can subscribe to to get information if user clicked "Allow" or "Don't allow" notifications but similar thing doesn't seem to exist for call action.
The docs state that the prompt will always appear when calling tel but since the prompt is made outside of your app, you can't do anything to observe it.
I feel I am the first one in the universe trying to get iOS swift working with Azure, not much help out there.
I followed this Create an iOS app
and then Add Push Notifications to your iOS App. I am supposed to be able to do a successful push notification from iPhone, but I get this error. btw: I can get my C# code to trigger in visual studio in my pc (using this tutorial), so the request seems to be working, but the response sucks. Any one knows how to fix it!!
Error registering for notifications: Optional("Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 \"{\"message\":\"An error has occurred.\"}\" UserInfo={com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey=<NSMutableURLRequest: 0x14cebf780> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C }, com.Microsoft.MicrosoftAzureMobile.ErrorResponseKey=<NSHTTPURLResponse: 0x14cec54b0> { URL: http://<mysite>.azurewebsites.net/push/installations/1E32E9B5-E976-4CCD-BD61-D026D3F4FF1C } { status code: 500, headers {\n \"Content-Length\" = 36;\n \"Content-Type\" = \"application/json; charset=utf-8\";\n Date = \"Wed, 11 May 2016 21:39:39 GMT\";\n Server = \"Microsoft-IIS/8.0\";\n \"Set-Cookie\" = \"ARRAffinity=8d79cd782ff16b44f7f280b76e2bc5564d86e0d1b228227b8e0033f4bb1c4582;Path=/;Domain=<mysite>.azurewebsites.net\";\n \"X-Powered-By\" = \"ASP.NET\";\n} }, NSLocalizedDescription={\"message\":\"An error has occurred.\"}}")
UPDATE #1
The only url I have is the one per the tutorial. The rest of the code is identical to the ones I mentioned in the links (I copied it character by character):
class ClientManager {
static let sharedClient = MSClient(applicationURLString: "http://<mysite>.azurewebsites.net")
}
UPDATE #2
#Pau Senabre I am working with swift not Objective-C per my question (see my tags under question), so I don't have an .m file per your step #1. I also don't have the logErrorIfNotNil you mentioned. My method (which is generated by Azure before modifications) looks like this:
#IBAction func addItem(sender : AnyObject) {
self.performSegueWithIdentifier("addItem", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
{
if segue.identifier == "addItem" {
let todoController = segue.destinationViewController as! ToDoItemViewController
todoController.delegate = self
}
}
UPDATE #3
#Pau Senabre My goal is to do mobile apps/services, not mobile engagement. See the difference here. btw: I had followed the azure engagement example when I started playing with it and had worked for me. But my need now is web/mobile apps. So, does what you suggested still apply for my need?
Could you please post some code? I think you may be using a wrong URL in a certain place.
To UPDATE #2
Check the following link:
https://github.com/Azure/azure-content/blob/master/articles/mobile-engagement/mobile-engagement-ios-swift-get-started.md
In section Modify your Application Delegate make sure you create a reach module and your existing Engagement initialization has all the init Values.
EngagementAgent.init("Endpoint={YOUR_APP_COLLECTION.DOMAIN};SdkKey={YOUR_SDK_KEY};AppId={YOUR_APPID}", modulesArray:[reach])
The error Code provided Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1302 matches to a bad request. If you are entering some data, make beforehand a Data Input Validation:
1 In the TodoService.m file, locate the addItem method search for the [self logErrorIfNotNil:error]; line of code. Beneath that line of code, replace the remainder of the completion block with the following code that checks to see if there was an error in the request and if that error code was –1302, indicating a bad request:
BOOL badRequest = ((error) && (error.code == -1302));
// detect text validation error from service.
if (!badRequest) // The service responded appropriately
{
NSUInteger index = [itemscount];
[(NSMutableArray *)itemsinsertObject:result atIndex:index];
// Let the caller know that we finished
completion(index);
}
2 Build and run; you can see in the Xcode output window that the bad request error from the service was handled:
2012-10-23 22:01:32.169 Quickstart[5932:11303] ERROR Error Domain=com.Microsoft.WindowsAzureMobileServices.ErrorDomain Code=-1302 “Text length must be under 10″ UserInfo=0x7193850 {NSLocalizedDescription=Text length must be under 10, com.Microsoft.WindowsAzureMobileServices.ErrorResponseKey=, com.Microsoft.WindowsAzureMobileServices.ErrorRequestKey=https://task.azure-mobile.net/tables/TodoItem>}
3 Finally, in the TodoService.m file, locate the logErrorIfNotNil method, which handles the logging of errors to the output window. Inside the if code block, just below the line NSLog(#”ERROR %#”, error); add the following if block:
// added to display description of bad request
if (error.code == -1302){
UIAlertView *av =
[[UIAlertView alloc]
initWithTitle:#”Request Failed”
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#”OK”
otherButtonTitles:nil
];
[av show];
}
Aditionally, review the following steps in the Azure Setup, maybe you are missing something at some point:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-ios-get-started-push/
1 Create a Notification Hub
This creates a new notification hub and connects it to your mobile app. If you have an existing notification hub, you can choose to connect it to your Mobile App backend instead of creating a new one.
2 Register app for push notifications
Register an App ID for your app. Create an explicit App ID (not a wildcard App ID) and for Bundle ID, use the exact Bundle ID that is in your Xcode quickstart project. It is also crucial that you check the Push Notifications option.
Next, configuring push notifications. You may create either a "Development" or "Distribution" SSL certificate (remember to select the corresponding option in the Azure portal later.)
3 Configure Azure to send push notifications
In the Azure portal, click Browse All > App Services > your Mobile App backend > Settings > Mobile > Push > Apple Push Notification Services > Upload Certificate. Upload the .p12 file, selecting the correct Mode (corresponding to whether the client SSL certificate you generated earlier was Development or Distribution.)
4 Update server project to send push notifications
Replace the PostTodoItem method with the following code:
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
// Get the settings for the server project.
HttpConfiguration config = this.Configuration;
MobileAppSettingsDictionary settings =
this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
// Get the Notification Hubs credentials for the Mobile App.
string notificationHubName = settings.NotificationHubName;
string notificationHubConnection = settings
.Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;
// Create a new Notification Hub client.
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString(notificationHubConnection, notificationHubName);
// iOS payload
var appleNotificationPayload = "{\"aps\":{\"alert\":\"" + item.Text + "\"}}";
try
{
// Send the push notification and log the results.
var result = await hub.SendAppleNativeNotificationAsync(appleNotificationPayload);
// Write the success result to the logs.
config.Services.GetTraceWriter().Info(result.State.ToString());
}
catch (System.Exception ex)
{
// Write the failure result to the logs.
config.Services.GetTraceWriter()
.Error(ex.Message, null, "Push.SendAsync Error");
}
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
this is the proper answer from another question I had earlier, which fixes both: Registration and Receiving push notifications. I said this in here:
I finally have been able to receive notifications last night. I went ahead and redid an entire walk-through of all apple-side installation steps using this tutorial: Sending push notifications to iOS with Azure Notification Hubs then the azure-side of things using this: Create an iOS app and Add Push Notifications to your iOS App. That took care of the registering the app of the device successfully, which I was able to verify using the note of AdrianHall in this thread. But that wasn't enough. The Azure tutorials fell short detailing the steps needed in Xcode, which I found here: [How To] Setup Remote Push Notification in iOS - Swift 2.0 Code I didn't have to setup any "push notification" in Xcode or anything like that.
I hope this detailed answer will save you many hours of digging through.
i build a register form for my app and i need to send the user a verifiation code by sms in order to complete the registration proccess.
i tried to use MFMessageComposeViewController but its open the dialog sms on the device so the user can see the code.
i also checked the web for 3party of sending sms but there is a problem with the country code. i know its posible becuse whatsapp do it to confirm the user.
what it the right way to do it?
this is the topic the i tried:
Sending SMS in iOS with Swift
The best way to achieve this is by creating some views for allowing the user to enter the phone number with the country code which can be used by a server to send a request for initiating the OTP verification. To achieve this you need to:
Create View Controllers.
Upload Phone Number and Country code to the server.
Validate the requests by verifying the OTP.
As mentioned by Dan, you can use Digits in Fabric for that purpose, and create custom views for a great UX.
On the other hand, you can also use a service called as SendOTP from MSG91 - you can use it for internal testing and development ideas as they provide you with 5,000 free OTP SMS. The service has a complete set of APIs which you can implement on the backend as well on the app front. Also, they provide a framework so that you don't need to create the views, but only presentViewController and call delegate methods for knowing what happened during the verification process - such as Cancelled or Verified or Failed.
Swift implementation of the same looks like this:
class OTPFrame: UIViewController, sendOTPAuthenticationViewControllerDelegate {
func loadOTPFramework() {
SendOTP.sharedManager().startWithApiId("yourAppID")
let frameworkPath: NSString = NSBundle.mainBundle().privateFrameworksPath!
let frameworkBundlePath: NSString = frameworkPath.stringByAppendingPathComponent("SendOTPFramework.framework")
let frameworkBundle : NSBundle
= NSBundle(path: frameworkBundlePath as String)!
let authenticationViewController: AuthenticationViewController = AuthenticationViewController(nibName: "AuthenticationViewController", bundle: frameworkBundle)
authenticationViewController.delegate = self self.presentViewController(authenticationViewController, animated: true, completion: nil)
}
func authenticationisSuccessfulForMobileNumber(mobNo: String!, withCountryCode countryCode: String!) {
print("Success")
}
func canceledAuthentication() {
print("Cancelled")
}
func authenticationisFailedForMobileNumber(mobNo: String!, withCountryCode countryCode: String!) {
print("Failed")
}
}
Disclaimer: I, in no way, endorse the services mentioned above - you are free to choose whatever you like.
Thank You!
I would give digits a try! It's part of the Twitter Fabric package and it's very simple to use. The user enters their phone number and Fabric takes care of validating the number.
I define a Challenge Handler,
var AuthRealmChallengeHandler = WL.Client.createChallengeHandler("AuthRealm");
AuthRealmChallengeHandler.isCustomResponse = function(response) {
//returns true or false
};
once I click the login button i send a request to the adapter:
var resourceRequest = new WLResourceRequest(
"/adapters/AuthAdapter/getSecretData", WLResourceRequest.GET,
30000);
resourceRequest.send().then(getSecretData_CallbackOK,
getSecretData_CallbackFail);
However, after closing the app, re-launching and the login button is pressed again, the isCustomResponse is not called again. Why is it so?
I've checked that the isUserAuthenticated returns true, however it still doesn't call isCustomResponse:
WL.Client.updateUserInfo();
if (WL.Client.isUserAuthenticated("AuthRealm")) {
}else{
}
In addition to changing the project settings as was mentioned in the comments, to answer the remaining questions:
There is no relation between the application session "state" to JSONStore. JSONStore is local to your app itself in the device and not to the network.
You can invoke the logout function on application initialization, as a way to ensure that the client will be logged out once you have re-started the app in order to simulate the expected behavior by you. You will likely also want to extend the splash screen duration while this action is done so the user experience will be better... the logout function needs to simply call WL.Client.logout (refer to the documentation for this).
I'm working on a Safari Content Blocking extension. I intend to show setup instructions if the extension is disabled and to show settings if it is conversely enabled. How can I determine if the extension is enabled by the user?
I've seen this method to detect if a custom keyboard is activated but there's no key on NSUserDefaults that relates to Safari Content Blockers.
As of iOS 10, there is a new method in SFContentBlockerManager to support this:
getStateOfContentBlocker(withIdentifier:completionHandler:)
And you call it like this (Swift 3):
SFContentBlockerManager.getStateOfContentBlocker(withIdentifier: "your.identifier.here", completionHandler: { (state, error) in
if let error = error {
// TODO: handle the error
}
if let state = state {
let contentBlockerIsEnabled = state.isEnabled
// TODO: do something with this value
}
})
You could utilize a SFSafariViewController to load a custom website. This website checks whether it is able to show something that your content blocker should block. Then redirect to the respective custom url (success/failure) that your app previously registered for. You could even use a hidden Safari View Controller without animation to avoid any distraction from the user's perspective (as shown here). (I guess this technique is used by former content blocker Peace)
Steps
App
Register custom URLs for success/failure
Register for notification callback using the NotificationCenter (e.g.
contentBlockerEnabled)
Use SFSafariViewController to show a custom website and include the following rule in blockerList.json:
{
"action": {
"type": "css-display-none",
"selector": ".blocked_selector"
},
"trigger": {
"url-filter": ".*"
}
}
Website
Check for blocked content:
if($('.blocked_selector').css('display') == "none") {
// Content blocker enabled
}
Redirect to custom URL (success/failure)
App
Post notification from
application:openURL:options: (success/failure based on called url)
Update 18/01
Following on from Tilo's hypothesis, I built the proposed solution. I wrote about what I learnt on Medium and you can grab the source files from GitHub.
TL;DR It works but only temperamentally due to the latency incurred of the content blocking rules database to update. A potential workaround is redirecting the test page to create an artificial delay.