I already have the .vcf
file saved on my local server (node.js)
and am running the WKWebView
on my iPhone as an iOS application. How can I download the .vcf
file from the WKWebView
app to my iPhone's contacts? When I try downloading the file on an actual browser, it works, but it doesn't work on the iOS WKWebView
app. Maybe, is there something like a download listener for iOS, similar to the one for android? Any help will be deeply appreciated. Stuck on it for quite long!! Thanks a ton!
Asked
Active
Viewed 900 times
0

Hasitha Jayawardana
- 2,326
- 4
- 18
- 36

Ian Bell
- 533
- 5
- 18
-
What do you mean by "iOS WKWebView app"? – Ganpat Jun 26 '19 at 12:08
-
It basically means loading my website in an iOS application. It's an updated version of the uiWebView that Swift used to have earlier. – Ian Bell Jun 26 '19 at 13:36
-
This is the link to the documentation- https://developer.apple.com/documentation/webkit/wkwebview#declarations It describes it as "an object that displays interactive web content, such as for an in-app browser." – Ian Bell Jun 27 '19 at 06:57
1 Answers
0
Part 1: Get VCF file URL from Website
Set script message handler on WKWebView
, use below code when initialising WKWebView
:
webView?.configuration.userContentController.add(self, name: "MyHandler")
You have to set WKScriptMessageHandler
delegate.
Add below code to your website's download button click event:
window.webkit.messageHandlers.MyHandler.postMessage({"message":"Start Download", "vcf_url":"https://www.yourwebsite.com/path/file.cvf"})
didReceiveScriptMessage
will called when user clicked on download button on website. Here you will receive ["message":"Start Download", "vcf_url":"https://www.yourwebsite.com/path/file.cvf"]
object.
Part 2: Get VCF file data and Add to Contacts
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print(message.body)
if let dic = message.body as? [String:String] {
if let url = dic["vcf_url"] {
let fileUrl = URL(fileURLWithPath: url)
do {
let data = try Data(contentsOf: fileUrl)
let contacts = try CNContactVCardSerialization.contacts(with: data)
let contactStore = CNContactStore.init()
contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (granted, accessError) -> Void in
if granted {
let saveRequest = CNSaveRequest()
for contact in contacts {
let newContact = CNMutableContact()
newContact.givenName = contact.givenName
newContact.familyName = contact.familyName
newContact.phoneNumbers = contact.phoneNumbers
saveRequest.add(newContact, toContainerWithIdentifier: "")
do {
try contactStore.execute(saveRequest)
// Contact saved successfully
} catch let error {
print("Error - \(error.localizedDescription)")
}
}
}
})
} catch let error {
print("Error - \(error.localizedDescription)")
}
}
}
Here, newContact.imageData = contact.imageData
can be used to save image if it is not nil
.
I have not illustrated all the property of contact in example, but you can use as you like.

Ganpat
- 768
- 3
- 15
- 30
-
Thanks for the response. However, could you please share on how to "Load the vcf file content in 'data' object"? Right now it gives me an error saying "Use of unresolved identifier 'data'; did you mean 'Data'?", so could you please share how can I resolve this issue? Thanks! – Ian Bell Jun 27 '19 at 08:49
-
The onclick event for the javascript side code also doesnt seem to be working. Snap of my website code (javascript)- "window.webkit.messageHandlers.MyHandler.postMessage({"message":"Start Download", "vcf_url":"./public/images/'User Onescan0.vcf"})" In the vcf_url, I specified the exact path of my .vcf file stored on my local server. Also, it doesn't show the "Start Download" message anywhere. – Ian Bell Jun 27 '19 at 10:34
-
That means something wrong on `WKWebKit` initialization part or may be `WKScriptMessageHandler ` delegate not implemented properly. Show your code for initialization of `WKWebkit`. – Ganpat Jun 27 '19 at 11:15
-
Oh No! You have initialized WKWebView from storyboard, so you have to change "let configuration = WKWebViewConfiguration() configuration.userContentController.add(self, name: "MyHandler")" to `webView?.configuration.userContentController.add(self, name: "MyHandler")`. Also add this before load request. – Ganpat Jun 27 '19 at 11:43
-
Now it displays the 'message' and 'vcf_url' as shown in the attached image link, however, it still doesn't save the vCard info (.vcf file) into my phone's contacts. Basically, how do I get the .vcf file into phone, and save it as a contact? I can't seem to locate the .vcf file in my phone as well. Image link to the print console in Xcode- https://i.stack.imgur.com/nWFHi.png – Ian Bell Jun 27 '19 at 12:06
-
This is how my 'User Onescan0.vcf' file looks like- https://i.stack.imgur.com/acIMr.png – Ian Bell Jun 27 '19 at 12:10
-
Are you getting any error? Add print statement after `try contactStore.execute(saveRequest)` line, so you can check process completed or not. – Ganpat Jun 27 '19 at 12:24
-
I checked with the print statement after try contactStore.execute(saveRequest) line, and it doesn't print anything, so the process is not getting completed. What could be the reason for this? – Ian Bell Jun 27 '19 at 12:28
-
Just add break point at `print(message.body)` then use `F6` key to check app flow, check from where control is exiting? – Ganpat Jun 27 '19 at 12:35
-
I actually checked by putting print statements at different positions in the code, so this is the link to code- https://i.stack.imgur.com/XAPfX.png And this is the link to the output of the code- https://i.stack.imgur.com/SJGzW.png – Ian Bell Jun 27 '19 at 12:48
-
Error comes while creating URL from your path string. Your URL string is invalid, use full path like http://127.0.0.1/images/file.vcf – Ganpat Jun 27 '19 at 13:55
-
Yeah I tried changing the path quite a lot, but it's still not working fine. I am attaching the screenshot of where exactly my .vcf file is located here- https://i.stack.imgur.com/JFC8O.png Also, I am attaching the screenshot of the vcf_url I have mentioned in my javascript- https://i.stack.imgur.com/7dz6S.png Since I am running using my IP address locally, am I specifying the path correctly even or no? I tried quite a lot of combinations but none seem to work. Please help me check. Thanks!! – Ian Bell Jun 27 '19 at 14:27
-
Like what would you think the valid URL string would be in this case? – Ian Bell Jun 27 '19 at 14:35
-
I figured the error in the previous one! There was a 'space' in the file name so it didn't read the full url. However, fixed that now, and it still showing an error but it executes more lines of code. I have attached the screenshot of the error here- https://i.stack.imgur.com/s3aC5.png And the code is attached here- https://i.stack.imgur.com/v3Txg.png – Ian Bell Jun 27 '19 at 15:24
-
try to create URL with this: `if let fileUrl = URL(fileURLWithPath: url) {` , also you need to add Contact permission in info.plist – Ganpat Jun 28 '19 at 04:40
-
I tried it, and it gives an error- "Initializer for conditional binding must have Optional type, not 'URL'" . Attaching the screenshot here- https://i.stack.imgur.com/pifEZ.png – Ian Bell Jun 28 '19 at 14:06
-
I tried using 'file://' befoe specifying the absolute path of the file URL on my system, so now it gives an error saying - 'The file 'UserOneScan0.vcf' cannot be opened as there is no such file.' However, the file exists for sure and when I open the file path via my javascript code, it is able to open. What might be the error in this case? – Ian Bell Jun 29 '19 at 08:01
-
Could you please help me with how to open a file by specifying its path in Swift? It seems that it is unable to locate the file even though it exists. Thanks! – Ian Bell Jul 01 '19 at 03:26
-
I tried using your previous code, with a very minor change, on emulator, and it worked well i.e. I was able to save the .vcf file as a contact on the emulator. However, when I tried it on my iPhone, it didn't work and gave the me the same error- "The file UserOnescan0.vcf' couldn't be opened because there is no such file." I gave the Contacts usage permission as well in info.plist. Is there any other permission or code required to save the .vcf file as a contact on actual iPhone rather than just the emulator? Here is the link to the code- "https://i.stack.imgur.com/61BTX.png" . – Ian Bell Jul 01 '19 at 07:14
-
Also, here is the screenshot of the error- "https://i.stack.imgur.com/rdUEi.png" . I have also printed the complete path name of .vcf file for your reference. Since this code worked perfectly on emulator, but not working on my iPhone, it means that the file actually exists, it's just it's not reading for the actual iPhone. Could you please help me resolve this? Thanks! – Ian Bell Jul 01 '19 at 07:20
-
I tried the updated code you posted above, but that doesn't seem to work as well, and it gives the same error, even for emulator, so the previous one you posted was better in the sense that it worked for emulator. – Ian Bell Jul 01 '19 at 07:30
-
This is because emulator can access files of your mac, but iPhone can't. – Ganpat Jul 01 '19 at 07:57
-
-
For testing purpose you can use any server for eg. XAMPP, and make sure iPhone and mac both are in the same network domain. – Ganpat Jul 01 '19 at 09:19
-
I am already using a server using node.js, which also makes sure that my mac and iPhone are connected to the same network, then only the application runs. When I open my webpage on my iPhone's safari browser, I am able to read the contents of the .vcf file which is indeed stored locally on my mac. However, when I try to read the contents of .vcf file from the iOS application on my iPhone, it is unable to do so. What could be the reason for such a difference, and how to resolve it, since both are running on my iPhone itself? – Ian Bell Jul 01 '19 at 10:18
-
I've been working on it continuously, however, it's still not working on iPhone. Could you please guide me on how to make it work on iPhone and save it as a contact in iPhone? Thanks a ton! – Ian Bell Jul 01 '19 at 16:11
-
Just a quick question, how to add a variable name inside the line: "window.webkit.messageHandlers.MyHandler.postMessage({"message":"Start Download", "vcf_url":"https://www.yourwebsite.com/path/file.cvf", "name": someVariable})" in javascript. Say I have a variable in my html code and I want to send it to swift using the above line, how do I add the variable here? Thanks a lot! – Ian Bell Jul 02 '19 at 14:21
-
see answer at: https://stackoverflow.com/questions/3304014/how-to-interpolate-variables-in-strings-in-javascript-without-concatenation – Ganpat Jul 03 '19 at 07:42