Opening an URL scanned from a QR code in SFSafariViewController - swift

I'm trying to make my app open the scanned url from qr codes. I made a qr code scanner but it only copies the value of the scanned qr code to the pasteboard. I'm trying to make it open it in a SFSafariViewController.
instead of "Copy" option, I want to make it "Open" and actually open the scanned url.
Here's my code
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if metadataObjects != nil && metadataObjects.count != 0
{
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
{
if object.type == AVMetadataObjectTypeQRCode
{
let alert = UIAlertController(title: "QR Code", message: object.stringValue, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
UIPasteboard.general.string = object.stringValue
}))
present(alert, animated: true, completion: nil)
}
}
}
}

Using safariviewController is pretty straightforward
First you have to import safariservices and then present the safaricontroller with a url
The basic codes to this are
import SafariServices
func loadSafari(url : String){
guard let url = URL(string: url) else { return }
let safariController = SFSafariViewController(url: url)
present(safariController, animated: true, completion: nil)
}
place this code in your class and call the function inside your capture output
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if metadataObjects != nil && metadataObjects.count != 0
{
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
{
if object.type == AVMetadataObjectTypeQRCode
{
UIPasteboard.general.string = object.stringValue
loadSafari(url: object.stringValue)
}))
present(alert, animated: true, completion: nil)
}
}
}
}
clicking on the done will dismiss the safariController and have the user navigate back to the previous viewcontroller.
I hope this helps. Let me know how it goes.

Your code shows no sign of attempting to use the SFSafariViewController. Have you tried something like the below?
import SafariServices
if let url = URL(string: object.stringValue) {
let browser = SFSafariViewController(url: url)
}
This won't make it magically appear, there will still be some work you need to do yourself to present it to the user such as:
presentViewController(browser, animated: true, completion: nil)

Related

How to show scanned QRCode user profile in my app in swift

First time i am working with QRCode
in our app i need to show the scanned user profile in my app when i scan that user QRCode in my app.. how to show scanned user profile in my app
i have written code for scan the user QRCode.. if i scan correct QRCode then here how to show that person profile in my app
code for scan the qrcode scanner:
import UIKit
import AVFoundation
class QRCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var video = AVCaptureVideoPreviewLayer()
let session = AVCaptureSession()
#IBOutlet weak var qrCode: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
guard let captureDevice = AVCaptureDevice.default(for: AVMediaType.video) else { return }
do{
let input = try AVCaptureDeviceInput(device: captureDevice)
session.addInput(input)
}catch{print("error")}
let output = AVCaptureMetadataOutput()
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue:DispatchQueue.main)
output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
video = AVCaptureVideoPreviewLayer(session: session)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
self.view.bringSubviewToFront(qrCode)
session.startRunning()
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if metadataObjects != nil && metadataObjects.count != 0{
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject{
if object.type == AVMetadataObject.ObjectType.qr{
let alert = UIAlertController(title: "QR Code", message: object.stringValue, preferredStyle: .alert)
alert.addAction(UIAlertAction(title:"Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title:"Confirm", style: .default, handler: { (nil) in
// self.scannedCode = object.stringValue!
self.session.stopRunning() }))
present(alert, animated: true, completion: nil)
}
}
}
}
}
by using above code if i scan correct QRCode of user, then how to show that person profile in my screen.. please suggest me..

Swift - Automatically save pdf file to Files app On My iPhone

I am in desperate need of help.
I am trying to create an app which allows the user to save the pdf file from a link such as the example one I gave in the subjectLinks array, all those links point to a pdf page and I am trying to download it and save it in my app. So far, I have scoured everywhere and found a way to do it using the Files app, so what I'm doing in the code is downloading the data of the pdf and opening it using UIDocument and presentPreview to display it and I have managed to allow the user to share the downloaded file and save it to Files as well.
However the problem arises as I want to make it so that when the user clicks download the file is automatically saved to the Files app in a directory so that the user does not need to click the option button then choose Save to Files and then look for where to save it. Is that possible??
If that is not possible, at least when the user chooses the option button and clicks Save to Files, it would automatically create a separate directory where the user can see and pdf file can be saved?
I want to do this as most times, when Save to Files is chosen, saving 'On My iPhone' is not available as there is no directory or such present so it can only be saved to google drive or iCloud Drive and this is a major inconvenience.
Sorry for the long post. BUT I WOULD BE EXTREMELY GRATEFUL IF ANYONE COULD HELP SOLVE MY PROBLEM. THANK YOU SOOOOO MUCH IN ADVANCE :)
P.S everything in my code works perfectly fine so far, its just I am absolutely clueless as to how to implement the features I have outlines above?
import UIKit
import StoreKit
class TableViewController: UITableViewController {
let documentInteractionController = UIDocumentInteractionController()
let subjectLinks = ["https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Accounting%20(9706)/2015%20Jun/9706_s15_qp_42.pdf", "https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Economics%20(9708)/2017%20Jun/9708_s17_qp_12.pdf", "https://pastpapers.papacambridge.com/Cambridge%20International%20Examinations%20(CIE)/AS%20and%20A%20Level/Mathematics%20(9709)/2018-May-June/9709_s18_qp_12.pdf"]
override func viewDidLoad() {
super.viewDidLoad()
documentInteractionController.delegate = self as? UIDocumentInteractionControllerDelegate
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subjectLinks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = subjectLinks[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
// 1
let shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Download" , handler: { (action:UITableViewRowAction, indexPath: IndexPath) -> Void in
// 2
let downloadMenu = UIAlertController(title: nil, message: "Download this paper", preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
downloadMenu.addAction(UIAlertAction(title: "Download", style: UIAlertActionStyle.destructive, handler: { action in self.storeAndShare(withURLString: self.subjectLinks[indexPath.row])}))
downloadMenu.addAction(cancelAction)
self.present(downloadMenu, animated: true, completion: nil)
})
// 3
let rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Rate" , handler: { (action:UITableViewRowAction, indexPath:IndexPath) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.default, handler: {action in SKStoreReviewController.requestReview()})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.present(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
}
extension TableViewController {
/// This function will set all the required properties, and then provide a preview for the document
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
/// This function will store your document to some temporary URL and then provide sharing, copying, printing, saving options to the user
func storeAndShare(withURLString: String) {
guard let url = URL(string: withURLString) else { return }
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let fileManager = FileManager.default
do {
let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = documentDirectory.appendingPathComponent("fileName.pdf")
try data.write(to: fileURL)
DispatchQueue.main.async {
self.share(url: fileURL)
}
} catch {
print(error)
}
}.resume()
}
}
extension TableViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
Example of download any pdf file and automatically save inside files folder of iPhone.
let urlString = "https://www.tutorialspoint.com/swift/swift_tutorial.pdf"
let url = URL(string: urlString)
let fileName = String((url!.lastPathComponent)) as NSString
//Mark: Create destination URL
let documentsUrl:URL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!
let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
//Mark: Create URL to the source file you want to download
let fileURL = URL(string: urlString)
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
//Mark: Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
do {
//Mark: Show UIActivityViewController to save the downloaded file
let contents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
for indexx in 0..<contents.count {
if contents[indexx].lastPathComponent == destinationFileUrl.lastPathComponent {
let activityViewController = UIActivityViewController(activityItems: [contents[indexx]], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
}
}
}
catch (let err) {
print("error: \(err)")
}
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
} else {
print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "")")
}
}
task.resume()
Step #1: Need to add permission in info.plist
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
Step #2: Download document from server url[any document]
func downloadPdf(sender:UIButton) {
DispatchQueue.main.async {
//Do UI Code here.
let pdfUrl = self.myOrderListModel?.myorderList?[sender.tag].invoiceUrl ?? ""
guard let fileURL = URL(string: pdfUrl) else { return }
var originalUrlStr : String = ""
print(fileURL.pathExtension)
if fileURL.pathExtension == ""{
originalUrlStr = pdfUrl + ".pdf"
} else {
originalUrlStr = pdfUrl
}
guard let originalUrl = URL(string: originalUrlStr) else { return }
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
let downloadTask = urlSession.downloadTask(with: originalUrl)
downloadTask.resume()
}
}
extension InvoiceViewController: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("File Downloaded Location- ", location)
guard let url = downloadTask.originalRequest?.url else {
return
}
let docsPath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let destinationPath = docsPath.appendingPathComponent(url.lastPathComponent)
try? FileManager.default.removeItem(at: destinationPath)
do{
try FileManager.default.copyItem(at: location, to: destinationPath)
print("File Downloaded Location- ", destinationPath)
DispatchQueue.main.async {
let urlString: String = destinationPath.absoluteString
self.saveInvoiceToDevice(filePath: urlString)
}
}catch let error {
print("Copy Error: \(error.localizedDescription)")
}
}
}
Step #3: Save downloaded file in Device "Files" Folder
func saveInvoiceToDevice(filePath : String) {
let fileURL = URL(string: filePath)
if FileManager.default.fileExists(atPath: fileURL!.path){
let url = URL(fileURLWithPath: fileURL!.path)
let activityViewController: UIActivityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView=self.view
//If user on iPad
if UIDevice.current.userInterfaceIdiom == .pad {
if activityViewController.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
}
}
self.present(activityViewController, animated: true, completion: nil)
}
else {
debugPrint("document was not found")
}
}

swift4 qr reader working but no result

swift4 qr-code reader and suppose to popup an alert, but it didn't show the popup alert.
The session start running properly, but the func captureOutput() seems not trigger when qr-code scanned.
my code:
import UIKit
import AVFoundation
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
#IBOutlet weak var square: UIImageView!
//Creating session
var video = AVCaptureVideoPreviewLayer()
override func viewDidLoad() {
super.viewDidLoad()
//Creating session
let session = AVCaptureSession()
//Define capture devcie
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
do
{let input = try AVCaptureDeviceInput(device: captureDevice!)
session.addInput(input)}
catch
{ print ("ERROR")}
let output = AVCaptureMetadataOutput()
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
video = AVCaptureVideoPreviewLayer(session: session)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
self.view.bringSubview(toFront: square)
session.startRunning()
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if metadataObjects != nil && metadataObjects.count != 0
{
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
{
if object.type == AVMetadataObject.ObjectType.qr
{
let alert = UIAlertController(title: "QR Code", message: object.stringValue, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
UIPasteboard.general.string = object.stringValue
}))
present(alert, animated: true, completion: nil)
}
}
}
}
}
Your scanning code check will be in the following delegate:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
Your code will be like this:
import UIKit
import AVFoundation
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
#IBOutlet weak var square: UIImageView!
//Creating session
var video = AVCaptureVideoPreviewLayer()
override func viewDidLoad() {
super.viewDidLoad()
//Creating session
let session = AVCaptureSession()
//Define capture devcie
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
do
{let input = try AVCaptureDeviceInput(device: captureDevice!)
session.addInput(input)}
catch
{ print ("ERROR")}
let output = AVCaptureMetadataOutput()
session.addOutput(output)
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
video = AVCaptureVideoPreviewLayer(session: session)
video.frame = view.layer.bounds
view.layer.addSublayer(video)
self.view.bringSubview(toFront: square)
session.startRunning()
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if metadataObjects != nil && metadataObjects.count != 0
{
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
{
if object.type == AVMetadataObject.ObjectType.qr
{
let alert = UIAlertController(title: "QR Code", message: object.stringValue, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Retake", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Copy", style: .default, handler: { (nil) in
UIPasteboard.general.string = object.stringValue
}))
present(alert, animated: true, completion: nil)
}
}
}
}
}

use of unresolved identifier 'result' swift 3

I'm writing a login page for my app and i'm getting this error
social media app , xcode 8.3.2 , swift 3
i've tried target membership in file inspector and nothing changed
also I removed test units (UITest and Test) and renew them , it didn't worked either.
at the line 41 I'm getting this error "use of unresolved identifier 'result'"
the picture below explains the code
Picture
import UIKit
class LoginViewController : UIViewController
{
#IBOutlet weak var txt_username: UITextField!
#IBOutlet weak var txt_password: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btn_log_in_click(_ sender: Any){
let server=MultipartUtility (Url:"http://x.x.x.x/appname-api/user/login/")
//I.m hiding the real ip and details for posting this
server.AddFormField("username", value: txt_username.text)
server.AddFormField("password", value: txt_password.text)
let task = URLSession.shared.dataTask(with: server.execute())
{Data,URLResponse,error in
if error != nil{
print(error as Any)
return
}
do{
let json = try JSONSerialization.jsonObject(with: Data!, options: .allowFragments)
if let json_result = json as? [String: Any]{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
}
else{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
catch{
}
}
task.resume()
}
}
if let json_result = json as? [String: Any]
{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
else
{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
else{
// Error in jsonSerialization
}

Share extension causes safari to hang in iphone

I am developing an iOS app that allows user to save urls, similar to the Pocket app. In the app I have a share extension that basically just save the url into a NSUserDefaults based on the app group. For some reason the share extension causes the mobile safari to hang (being non responsive) after selecting the share extension. The code for the share extension is so simple, I am wondering what may have caused it. On debugging in Xcode, the function in the share extension is not being called at all too it seems. Any clues? This is running on iOS 9.3.
Here is the code:
//
// ShareViewController.swift
// intrafeedappShare
//
// Created by Dicky Johan on 5/21/16.
// Copyright © 2016 Dicky Johan. All rights reserved.
//
import UIKit
import Social
import MobileCoreServices
class ShareViewController: UIViewController {
var selectedURL: String?
override func viewDidLoad() {
super.viewDidLoad()
let contentType = kUTTypeURL as String
guard let item = self.extensionContext?.inputItems.first as? NSExtensionItem else {
fatalError()
}
for attachment in item.attachments as! [NSItemProvider] {
if attachment.hasItemConformingToTypeIdentifier(contentType) {
attachment.loadItemForTypeIdentifier(kUTTypeURL as String, options: nil) { url, error in
if error == nil {
guard let url = url as? NSURL else {
self.extensionContext?.cancelRequestWithError(NSError(domain:"Url is empty",code:-1,userInfo: nil))
return
}
self.selectedURL = url.absoluteString
let defaults = NSUserDefaults(suiteName: Constants.Settings.sharedAppGroup)
if let arrUrls = defaults!.objectForKey(Constants.Settings.sharedURLS) {
// append to the existing list
arrUrls.appendString(url.absoluteString)
} else {
let newArrUrl = [url.absoluteString]
defaults!.setObject(newArrUrl, forKey: Constants.Settings.sharedURLS)
}
defaults!.synchronize()
self.extensionContext?.completeRequestReturningItems(nil, completionHandler: nil)
let alert = UIAlertController(title: "Success", message: "Added url to intrafeed", preferredStyle: .Alert)
let action = UIAlertAction(title: "Done", style: .Default) { _ in
self.dismissViewControllerAnimated(true, completion: nil)
}
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
} else {
self.extensionContext?.cancelRequestWithError(error)
let alert = UIAlertController(title: "Error", message: "Error loading url", preferredStyle: .Alert)
let action = UIAlertAction(title: "Error", style: .Cancel) { _ in
self.dismissViewControllerAnimated(true, completion: nil)
}
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
}
}
}
Ok, apparently there was a crash in the code, thus causing the Safari to freeze. On debugging the extension in Xcode, I found the issue.