provideCredentialWithoutUserInteraction method not getting called for autofill extension - ios

I am developing password manager App with autofill Credential Provider extension.
method provideCredentialWithoutUserInteraction of ASCredentialProviderViewController is not getting called or not able to trace via breakpoint.
Code I have tried so far:
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) {
print(credentialIdentity.serviceIdentifier.identifier)
let credToProvide = ASPasswordCredential(user: "udayyy", password: "paasssss")
self.extensionContext.completeRequest(withSelectedCredential: credToProvide, completionHandler: nil)
}
also not able to print any logs.
Can any one help me with how to debug this method?
What exactly I want show my custom password on top of the keyboard.(shown in below left image)

Related

How to call `beginRequest` of Call Directory Extension?

I have to test about Call Blocking & Identification. So I followed the steps below.
(1) Create a Call Directory Extension in my project from [File] > [New] > [Target].
(2) Add a logging in Call Directory Extension to test.
class CallDirectoryHandler: CXCallDirectoryProvider {
override func beginRequest(with context: CXCallDirectoryExtensionContext) {
print("test")
}
}
(3) Call reload function of CallKit on my project.
CXCallDirectoryManager.sharedInstance.reloadExtension(withIdentifier: "EXTENSION_BUNDLE_IDENTIFIER", completionHandler: { (error) in
if let error = error {
print(error.localizedDescription)
} else {
print("success")
}
})
(4) Check my app is enabled in Settings > Phone > Call blocking & identification.
And success of 3 is printed, but test of 2 isn't printed.
Is there anything I should check?
Thanks in advance.
I think it is being called correctly as you can check the response on your app target sandbox.
The only way I know to get access to the logs in this case is by going in the Devices window of Xcode and looking at the device console, you should be able to see logs like this:
com.apple.CallKit.CallDirectory: ...
You might also try to debug it by putting directly a breakpoint in this line:
print("test")
Check also tutorials on finding out if you have any issue in the setup between your extension and your app sandboxes, there is a good one here: https://pusher.com/tutorials/callkit-ios-part-1

Handing a response in a controller after segueing to another controller

I'm using Cloudinary to store images that the user uploads in my Swift 2 app. I have a question about the flow/architecture. Currently what I'm doing is that as soon as the user uploads the image, I send the image to Cloudinary, send the image id to my server, and immediately segue the user to the next screen. With the id, I can later reference the image on Cloudinary, so I technically don't need to wait for the response back from Cloudinary and keep the user waiting. Yes, if there is an upload failure, I won't know, but those are edge cases. This is the code I have:
#IBAction func btnRegister(sender: AnyObject) {
let pictureId = self.btnImage.currentImage == NSUUID().UUIDString
self.uploadToCloudinary(pictureId)
//send to my server
User.register(_userName, password: _password, picture: pictureId)
.success { (value) in
self.performSegueWithIdentifier("Home", sender: self)
}
}
func uploadToCloudinary(pictureId:String){
let image = UIImagePNGRepresentation(btnImage.currentImage!)! as NSData
let uploader = CLUploader(_cloudinary, delegate: self)
uploader.upload(image, options: ["public_id":pictureId], withCompletion:onCloudinaryCompletion, andProgress:onCloudinaryProgress)
}
func onCloudinaryCompletion(successResult:[NSObject : AnyObject]!, errorResult:String!, code:Int, idContext:AnyObject!) {
//
}
However, I now realized that I need to save some additional details such as "version" that Cloudinary sends me back, so I might need to do something on onCloudinaryCompletion to send those details to my server. The thing is--that means I have to now make the user wait till the image finishes uploading before I can segue them to the next screen.
So my questions:
In Swift, can I still do stuff in the completion handler even if the user has segeued away to another view controller? That way I can keep my current flow, and just save the successResult whenever it returns, but I don't have to keep my user waiting.
Is there another recommended flow for doing something like this? Any suggestions welcome.
For those of you who are familiar with Cloudinary--is there a way to know the version before uploading? Because all I really need is the version, and if I can know that before uploading, I can save that along with the picture Id, and forget about the onCloudinaryCompletion.
From Cloudinary perspective you could use one of the following approaches:
Avoid using versions - URL versions are basically just a mean for busting the cache in case the image is updated. If this isn't essential then you can just remove it from the URL.
See: https://support.cloudinary.com/hc/en-us/articles/202520912-What-are-image-versions-
Use our Webhooks support - this will tell Cloudinary to notify your server with all the necessary details (including Public ID and Version) regarding the uploaded file, which you can then store together on your DB.
See: http://cloudinary.com/blog/webhooks_upload_notifications_and_background_image_processing

What makes a user discoverable to CKDiscoverAllUserIdentitiesOperation?

I am trying to discover contacts for a user with the code below (the code is in an implementation of a UITableViewController. I put breakpoints in both code blocks, and I determined that the the userIdentityDiscoveredBlock is not called while the completionBlock is called. This indicates that the operation is being run as expected, it just isn't finding any contacts.
I am running on the simulator, but I verified that the simulator has synced all my iCloud contacts (opening the Contacts app on the simulator shows all my contacts).
override func viewDidLoad() {
super.viewDidLoad()
let op = CKDiscoverAllUserIdentitiesOperation()
op.discoverAllUserIdentitiesCompletionBlock = { error -> Void in
// reload my data table
}
op.userIdentityDiscoveredBlock = { user -> Void in
if user.hasiCloudAccount {
self.iCloudUsers.append(user)
} else {
self.nonICloudUsers.append(user)
}
}
CKContainer.default().add(op)
}
So my question is this - Is there something else that has to be done in order to discover contacts? Is this a simulator issue?
I searched the documentation and other questions but I can't seem to find information on this given the operation is new to iOS 10.
There's quite a bit that must be done before CKDiscoverAllUserIdentitiesOperation will return any results.
First, each user of your app must grant permission to be looked up by email. Your app makes this request using CKContainer requestApplicationPermission.
Each user of your app must also be logged into an iCloud account. iCloud Drive must also be enabled by the user.
And lastly, for CKDiscoverAllUserIdentitiesOperation to return any users, the person must have contacts with email addresses that match other users that completed all of the previous steps.

iOS UI Test: how to get message of UIAlertController

My app has a login screen. If the user presses the login button without entering any text in either the username or password fields, the app will display a UIAlertController with an error message.
I am trying to model this logic in UI Tests, and want to assert that the UIAlertController is displaying the correct message. However, I can't find a way for the UI Test to access the message property of the alert. Here is the code generated by the test recorder:
func testLoginWithoutPasswort() {
let app = XCUIApplication()
let emailTextField = app.textFields["email"]
emailTextField.tap()
emailTextField.typeText("xxx#gmail.com")
app.buttons["Login"].tap()
app.alerts["Error"].collectionViews.buttons["OK"].tap()
}
Is there any way I can extract the String value of the alert's message, so I can put an assertion on it?
You can't directly test the alert's message. You can, however, test if the alert contains your error message's copy (at all).
For example, say your alert looks like this:
To assert that the alert contains the "Final Score" message, use:
XCTAssert(app.alerts.element.staticTexts["Final Score: 27 - 25"].exists)
You can also test the title of the alert directly:
XCTAssertEqual(app.alerts.element.label, "You won!")
More examples available in my UI Testing Cheat Sheet and Examples post and sample app.
I think it is: alert.elements()[2].name()
Inside onAlert callback function add alert.logElementTree() to see AlertView elements. It might be nil, maybe just title is shown.
Further to the answers above, which I struggled to get to work, there is another way.
Creata a Bool within your UItest method that is false:
var alertPressed = false
Then add a UIInterruptionMonitor and set the bool to true within it's closure:
addUIInterruptionMonitor(withDescription: "System Dialog") {
(alert) -> Bool in
alert.buttons["Allow"].tap()
alertPressed = true
return true
}
Then interact with the app again, and assert that the Bool is true
app.tap()
XCTAssert(alertPressed)
I hope this is helpful to someone.

How to test if "Allow Full Access" permission is granted from containing app?

I'm working on a keyboard extension project. At some points of the application code I need to test if the user have granted the "Allow Full Access" permission for the keyboard extension. The deal is that I need to do those tests from the application side, and based on this let the user to access keyboard settings or alert him in case the permission wasn't granted.
The problem is that the methods that provided here like:
func isOpenAccessGranted() -> Bool {
return UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)
}
or:
func isOpenAccessGranted() -> Bool {
let fm = NSFileManager.defaultManager()
let containerPath = fm.containerURLForSecurityApplicationGroupIdentifier(
"group.com.example")?.path
var error: NSError?
fm.contentsOfDirectoryAtPath(containerPath!, error: &error)
if (error != nil) {
NSLog("Full Access: Off")
return false
}
NSLog("Full Access: On");
return true
}
Working only from the keyboard side, as the keyboard is the only one that is affected from this permission. From the containing app side both of those methods always return true.
Does someone knows a reliable way to test this from the application side?
Consider using NSUSerdefaults in your app and keyboard. In order for an extension and app to be able to share the same NSUserdefaults, you can simply turn on App Groups. Select your main app target under your project in the project navigator and go to capabilities and enable App Groups by toggling it to on, adding your Developer profile and fixing the possibly arising issues.
Now create a new container. According to the help, it must start with “group.”, so give it a name like “group.com.mycompany.myapp”. Select your Today Extension target and repeat this process of switching on app groups. Don’t create a new one, rather select this newly created group to signify that the Today Extension is a part of the group.
This will now allow you to share the same NSUserdefaults as your container app.
All you have to do now is use the code you provided and add the saving method to the NSUserdefaults like so:
func isOpenAccessGranted() -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
let fm = NSFileManager.defaultManager()
let containerPath = fm.containerURLForSecurityApplicationGroupIdentifier(
"group.com.example")?.path
var error: NSError?
fm.contentsOfDirectoryAtPath(containerPath!, error: &error)
if (error != nil) {
NSLog("Full Access: Off")
defaults.setBool(false, forKey: "hasFullAccess")
return false
}
NSLog("Full Access: On");
defaults.setBool(true, forKey: "hasFullAccess")
return true
}
Do this in your keyboard extension. And then in your parent app, simply retrieve them and act upon their value.
let hasFullAccess : Bool = NSUserDefaults.standardUserDefaults().boolForKey("hasFullAccess")
if hasFullAccess{
//User granted full access
}
else{
//User didn't grant full access
}
If the user didn't grant full access the show an alert, else code away!
EDIT:
After contacting Apple's Technical Developer support they told me that this is not possible to achieve in any supported way as of right now. Their response is below:
Our engineers have reviewed your request and have concluded that there
is no supported way to achieve the desired functionality given the
currently shipping system configurations.
If you would like for Apple to consider adding support for such
features in the future, please submit an enhancement request via the
Bug Reporter tool at https://developer.apple.com/bug-reporting/.
Hope that helps, Julian
You can easily test whether the "Allow Full Access" permission is granted on iOS 11 and later.
To get the "Allow Full Access" permission, first subclass the
UIInputViewController class.
Add the code. The code returns a bool value.
Objective-C
[self hasFullAccess];
Swift
self.hasFullAccess
https://developer.apple.com/documentation/uikit/uiinputviewcontroller/2875763-hasfullaccess?changes=_2
Objective-C
[UIInputViewController new].hasFullAccess;

Resources