I created a file and I want to share it via UIDocumentInteractionController.
I am unsure on how to obtain the URL from the documentsPath and destination path where I saved my file
let someText = NSString(string: "Test")
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let destinationPath = documentsPath.stringByAppendingPathComponent("Data.txt")
var error:NSError?
let written = someText.writeToFile(destinationPath,
atomically: true,
encoding: NSUTF8StringEncoding,
error: &error)
if written{
println("Successfully stored the file at path \(destinationPath)")
let dic = UIDocumentInteractionController()
self.dic.URL = url
let v = sender as UIView
let ok = self.dic.presentOpenInMenuFromRect(
v.bounds, inView: v, animated: true)
Revise your code to the following
import UIKit
class ViewController: UIViewController {
var docController:UIDocumentInteractionController!
override func viewDidLoad() {
let someText = NSString(string: "Test")
if let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as? String {
let destinationPath = documentsPath.stringByAppendingPathComponent("Data.txt")
var error:NSError?
let written = someText.writeToFile(destinationPath,
atomically: true,
encoding: NSUTF8StringEncoding,
error: &error)
if written{
println("Successfully stored the file at path \(destinationPath)")
}
if let url = NSURL(fileURLWithPath: destinationPath) {
docController = UIDocumentInteractionController(URL: url)
}
}
}
#IBAction func sendFile(sender:AnyObject) {
docController.presentOptionsMenuFromRect(sender.frame, inView:self.view, animated:true)
}
}
Now wire up the IBAction to a button in the storyboard. Next:
click on the blue project icon in the left sidebar and then select
Info from the horizontal menu.
expand Document Types and enter "txt" in the Name field and
"public.data, public.content" in the Types field
now expand Exported UTIs and enter "txt" in the Description
field, "kUTTypeText" in the Identifier field and
"public.data, public.content" in the Conforms to field
So that everything looks like this:
You can now build and run the app to test.
Related
iam using the following code to show the sharing options for PDF
self.documentController = UIDocumentInteractionController(url: url)
self.documentController.name = "Test name" // not working
self.documentController.presentOptionsMenu(from: self.shareButton, animated: true)
the problem is that I save the PDF file name with datestamp to avoid having two files with the same name, but when the share options is being shown the actual file name appears,
is there is a way to show custom name instead of the actual filename (I don't want to copy the file to other place and rename it, waste of time and performance)
In such a situation, we can create a temporary folder which can contain the same file with lastPathExtension will be document.fileExtension and we can pass this newly file path to UIDocumentInteractionController.init(url: newFileUrl)
For Example:
func openUnsupportedFileWithPath(documentName : String, fileurl : URL, fileExtension : String, aDocument: SILDocumentDB? = nil, sourceView: UIView? = nil) -> Void {
// Create new temporary path
let paths: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
var newFileUrl: String = paths.appending("/Downloads/TemporaryFolder)")
newFileUrl = newFileUrl.appendingFormat("%#","\(documentName)")
let destinationPathUrl : URL
do {
// Move newly filePath with new fileName and fileExtension
destinationPathUrl = URL(fileURLWithPath: destinanewFileUrltionPath)
try FileManager.default.moveItem(at: fileurl, to: destinationPathUrl)
} catch {
print(error)
}
//Pass newly filePath to UIDocumentInteractionController
documentInteractionController = UIDocumentInteractionController.init(url: newFileUrl)
documentInteractionController?.name = documentName
documentInteractionController?.delegate = self
let canPreview = documentInteractionController?.presentPreview(animated: true)
if (canPreview == false) {
let activityViewController = UIActivityViewController.init(activityItems: [fileurl], applicationActivities: nil)
activityViewController.setValue(documentName, forKey: "subject")
if ISIPAD {
activityViewController.popoverPresentationController?.sourceView = sourceView ?? self.view
}
self.present(activityViewController, animated: true, completion: nil)
}
}
And UIDocumentInteractionController get dismiss, remove the temporary filePath on documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) method.
public func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
documentInteractionController = nil
let paths: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath: String = paths.appending("/Downloads/TemporaryFolder)")
let _fileManager : FileManager = FileManager.default
if filePath.length > 0 {
if _fileManager.fileExists(atPath: filePath) {
do{
try _fileManager.removeItem(atPath: filePath)
}catch let error as NSError{
print("\(error.localizedDescription)")
}
}
}
}
I am trying to share photo from my iOS app to instagram app using UIDocumentInteractionController and I want to show only instagram app in popover. As instagram describe here it's possible but it not works for me, I don't know what I am missing.
Below is screenshot of instagram, that confirms it's possible.
Below is the code I am using for this.
#IBAction func sharePhoto(btn: UIButton) {
let photoBundlePath = Bundle.main.url(forResource: "Photo", withExtension: ".png")
do {
let data = try Data(contentsOf: photoBundlePath!)
let fileSavedPath = saveFile(data: data, name: "photo", fileExtension: ".igo")
let instagramUrl = URL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramUrl!) {
ic = UIDocumentInteractionController(url: fileSavedPath)
ic.delegate = self
ic.uti = "com.instagram.exclusivegram"
ic.presentOptionsMenu(from: btn.frame, in: self.view, animated: true)
ic.annotation = ["InstagramCaption" : "Testing"]
} else {
print("Instagram is not present in your device")
}
} catch {
print(error)
}
}
func saveFile(data: Data, name: String, fileExtension: String) -> URL {
let fileManager = FileManager.default
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentDirectory = paths[0]
let fullPath = documentDirectory + "/" + name + fileExtension
fileManager.createFile(atPath: fullPath, contents: data, attributes: nil)
return URL(fileURLWithPath: fullPath)
}
One more thing here is why Instagram is shown with text "Copy to" as one can see in below image.
I am generating a PDF of a UIView and storing with a name in myforms the PFD is being generated and console prints PDF is Available but it shows nothing but a white screen in VC
here is what I am doing :
I have this code to generate a PDF
#IBAction func createAct(_ sender: Any) {
print("Creat PDF")
self.createPdfFromView(mainView: mainView, saveToDocumentsWithFileName: "myforms")
}
func createPdfFromView(mainView: UIView, saveToDocumentsWithFileName fileName: String)
{
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, mainView.bounds, nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
mainView.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + fileName
debugPrint(documentsFileName)
pdfData.write(toFile: documentsFileName, atomically: true)
}
}
then I have this in console :
Creat PDF
"/Users/jawaidahmed/Library/Developer/CoreSimulator/Devices/3F95BE09-0F25-427C-9ED9-4BDB16DC3600/data/Containers/Data/Application/1EC22FBC-79E7-4AC5-BB7D-13783CC34516/Documents/myforms"
and I am using this PDFViewController to retrieve the file in a webview
override func viewDidLoad() {
super.viewDidLoad()
let check = "myforms"
var pdfURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
print("check final = \(pdfURL)")
pdfURL = pdfURL.appendingPathComponent(check) as URL
if let pdfBundleURL = Bundle.main.url(forResource: "myforms", withExtension: nil, subdirectory: nil) {
do {
let data = try Data(contentsOf: pdfBundleURL)
//Lastly, write your file to the disk.
try data.write(to: pdfURL, options: .atomicWrite)
}
catch {
// catch errors here
}
}
do{
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = URL(fileURLWithPath: path)
var filePath = url.appendingPathComponent(check).path
let fileManager1 = FileManager.default
if fileManager1.fileExists(atPath: filePath) {
print("FILE AVAILABLE in VC")
filePath = "file://\(filePath)"
let fileUrlkk = Foundation.URL(string: filePath)
let data = try Data(contentsOf: fileUrlkk!)
self.webView.load(data, mimeType: filePath, textEncodingName:"utf-8", baseURL: pdfURL.deletingLastPathComponent())
} else {
print("FILE NOT AVAILABLE in VC")
}
}
catch let error as NSError {
print("An error took place: \(error)")
}
}
And I am receiving this in console :
FILE AVAILABLE in VC
It means file is generated and available but it shows only empty VC white background only
self.webView.load(data, mimeType: "application/pdf", textEncodingName:"utf-8", baseURL: pdfURL.deletingLastPathComponent())
replace textEncodingName:""
with
textEncodingName:"utf-8"
check it
Try this for loading in Webview.I tried with your sample..It works
let FileName = "myforms"
let Filemanager = NSFileManager.defaultManager()
let docURL = Filemanager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
print(docURL)
let pdfPATH = docURL.URLByAppendingPathComponent(FileName)
print(pdfPATH)
let data = NSData(contentsOfURL: pdfPATH)
WBview.loadData(data!, MIMEType: "application/pdf", textEncodingName: "utf-8", baseURL: pdfPATH.URLByDeletingLastPathComponent!)
I am using Swift 4, Xcode 9, and development target iOS 11.0.
I am trying to append a custom folder (MyFolder) to the path variable.
let outputFilePath = (NSTemporaryDirectory() as NSString).appending("MyFolder").appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
But builder is giving error message:
appendingPathComponent' is unavailable: Use appendingPathComponent on URL instead.
I know, I am doing some silly mistake. Can you kindly help me in this?
Use this line
URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("MyFolder").appendingPathComponent(outputFileName).appendingPathExtension("mov")
instead of
(NSTemporaryDirectory() as NSString).appending("MyFolder").appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!)
This will return you a url and use url.Path to get its path in string .
Hope this helps you.
Check below code for reference in document Directory
class func getDocumentsDirectory() -> URL {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let dataPath = documentsDirectory.appendingPathComponent("FolderName")
do {
try FileManager.default.createDirectory(atPath: dataPath.path, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
print("Error creating directory: \(error.localizedDescription)")
}
return dataPath
}
For Appending Files in Folder You can use this
//name for file to be added
let uuid = UUID().uuidString
// storing a Audio File in Directory
let audioFilename = getDocumentsDirectory().appendingPathComponent("\(uuid).m4a")
To get Names of Files Available in the respected Folder created
//This function returns a Array with file names Available
class func getListOfRecordingsAvailable() -> [String] {
var fileNameArray = [String]()
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let myFilesPath = documentDirectoryPath.appending("/FolderName")
let files = FileManager.default.enumerator(atPath: myFilesPath)
while let file = files?.nextObject() {
//myfilesPath - Path
//file - fileName
fileNameArray.append(file as! String)
}
print(fileNameArray)
return fileNameArray
}
I made an pdf creator app. After creating pdf file I want to display the created files on a tableview. I created Tableview Controller and DocumentDirectoryTableTableViewController. I don't know how to do it after all of that.
I found this and this questions but I couldn't implement it into my code.
Also better to add my code for saving file:
// 5. Save PDF file
let path = "/MyApp/PdfFiles/MyPDF.pdf"
pdfData.write(toFile: path, atomically: true)
print("open \(path)") // command to open the generated file
UPDATE:
I can also get the App Directory and use it by this function:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
and
let path = "\(getDocumentsDirectory())MyApp.pdf"
If you have NSData for the pdf file you're trying to store and if you want user to access it, you can write it using this:
func writePDF(data: NSData, to Name:String) -> Bool {
let pdfData:NSData = data
let pdfPaths:[String] = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
var pdfPath = pdfPaths[0]
pdfPath.append("_\(Name).pdf")
let result:Bool = pdfData.write(toFile: pdfPath, atomically: true)
return result
}
If you want to read pdf file programatically in your app given that you store it in the above path. It can be done using this:
func readPDF(Name: String) {
let pdfPaths:[String] = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
var pdfPath = pdfPaths[0]
pdfPath.append("_\(Name).pdf")
if let pdfData:NSData = NSData(contentsOfFile: pdfPath) { // verifying pdf exists in this path
let documentController: UIDocumentInteractionController = UIDocumentInteractionController(url: URL(fileURLWithPath: pdfPath))
documentController.delegate = self
documentController.presentPreview(animated: true)
}
}
// the below delegate function for `UIDocumentInteractionController` is necessary for it to present in the current `UIViewController`
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}