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)")
}
}
}
}
Related
I try to save given video locally after then I need those saved videos for playing video in my app. I can't handle the saving video. Here is my saving try :
func saveVideoDocumentDirectory(url : URL){
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(".MOV")
do{
let videoData = try Data(contentsOf: url)
fileManager.createFile(atPath: paths as String, contents: videoData, attributes: nil)
}catch{
//
}
}
here is the get file try
func getVideo(){
let fileManager = FileManager.default
let videoPAth = (self.getDirectoryPath() as NSString).appendingPathComponent(".MOV")
if fileManager.fileExists(atPath: videoPAth){
print(videoPAth)
play(url: URL(string: videoPAth)!)
}else{
print("No Video")
}
}
here is my play video func :
func play(url : URL)
{
let player = AVPlayer(url: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
{
playerViewController.player!.play()
}
}
Instead of Filemanager.createFile(), try using write instead.
let videoData = try Data(contentsOf: url)
try videoData.write(to: paths, options: .atomic)
Also, I recommend creating a folder first (from this answer).
extension URL {
static func createFolder(folderName: String) -> URL? {
let fileManager = FileManager.default
// Get document directory for device, this should succeed
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
// Construct a URL with desired folder name
let folderURL = documentDirectory.appendingPathComponent(folderName)
// If folder URL does not exist, create it
if !fileManager.fileExists(atPath: folderURL.path) {
do {
// Attempt to create folder
try fileManager.createDirectory(atPath: folderURL.path,
withIntermediateDirectories: true,
attributes: nil)
} catch {
// Creation failed. Print error & return nil
print(error.localizedDescription)
return nil
}
}
// Folder either exists, or was created. Return URL
return folderURL
}
// Will only be called if document directory not found
return nil
}
}
Then, you can save like this:
guard let folderURL = URL.createFolder(folderName: "StoredVideos") else {
print("Can't create url")
return
}
let permanentFileURL = folderURL.appendingPathComponent(nameOfYourFile).appendingPathExtension("MOV")
let videoData = try Data(contentsOf: url)
try videoData.write(to: permanentFileURL, options: .atomic)
This will save you the hassle of NSSearchPathForDirectoriesInDomains.
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 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
}
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.