Open p12 files on ios device - ios

I have this requirement to download .p12 file(certificate) from a vendor and make it available on my app for the user to install it on to his device.
Now If I attach a .p12 file to email and when the recipient clicks on the file on iphone it will start installing I am just trying to get the same behavior.
As of now in my app I am able to download the p12 file and store it in the apps documents directory.
func saveCert(serialId : String){
let source = "https://myhost.com/serialId"
let url = NSURL(string: source)
let request = NSURLRequest(URL: url!)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if (error == nil) {
let statusCode = (response as! NSHTTPURLResponse).statusCode
print("Success: \(statusCode)")
let filename = self.getDocumentsDirectory().stringByAppendingPathComponent("test.p12")
print(filename)
data?.writeToFile(filename, atomically: true)
let filemgr = NSFileManager.defaultManager()
if filemgr.fileExistsAtPath(filename) {
print("File exists")
} else {
print("File not found")
}
}
else {
print("Faulure: %#", error!.localizedDescription);
}
});
task.resume()
}
Now i need to open this file so user will be taken to install profile screens. Please help.

Here is what you want to look at.
and here is an example of how to use it
import Security
let fileManager = NSFileManager.defaultManager()
var resourcePath:String = fileManager.currentDirectoryPath
resourcePath = resourcePath.stringByAppendingString("/dummy.p12")
if fileManager.fileExistsAtPath(resourcePath){
let p12Data: NSData = NSData(contentsOfFile: resourcePath)!
let key : NSString = kSecImportExportPassphrase as NSString
let options : NSDictionary = [key : "password_for_certificate"]
//create variable for holding security information
var privateKeyRef: SecKeyRef? = nil
var items : CFArray?
let securityError: OSStatus = SecPKCS12Import(p12Data, options, &items)
}
Hope that gets you most of the way there.
Edit:
After doing more research, I found this lib that will help you do everything you are looking to do.
Give it a try.

Related

iOS: How can app extension copy file to app Documents/ folder?

In the app extension is there a way to get file and copy it to Documents// folder?
I can get file with the code below. But how to copy it? I alway have an error
for item in self.extensionContext!.inputItems as! [NSExtensionItem] {
for provider in item.attachments! as! [NSItemProvider] {
provider.loadItem(forTypeIdentifier: provider.registeredTypeIdentifiers.first! as! String, options: nil, completionHandler: { (fileURL, error) in
if let fileURL = fileURL as? URL {
self.url = fileURL
// self.extensionOpenUrl(App.associatedDomain + fileURL.absoluteString)
}
})
}
}
copy by click:
let fileManager = FileManager.default
let pathForDocumentsDirectory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: App.group)!.path
let fileURL = self.url!
let name = fileURL.lastPathComponent
let copiedPath = pathForDocumentsDirectory
do {
try fileManager.copyItem(atPath: fileURL.absoluteString, toPath: copiedPath)
if fileManager.fileExists(atPath: copiedPath) {
print("fileExists!!!")
}
} catch let error as NSError {
print("error in copyItemAtPath")
print(error.localizedDescription)
}
file url:
file:///var/mobile/Media/PhotoData/OutgoingTemp/3CEC8D4A-9B1B-468B-A919-7C70C9C522B3/IMG_5484.jpg
path to copy:
/private/var/mobile/Containers/Shared/AppGroup/D7D2317B-9C57-424D-9D2F-209C62BBFAE5/IMG_5484.jpg
error:
The file “IMG_5484.jpg” couldn’t be opened because you don’t have permission to view it.
You can't do that. Extensions can communicate with the main app only by leaving/modifying the files in the App Group space (which means also that you must create the App Group first in the developer portal and add proper entitlements).

UNNotificationAttachment set image URL to Caches directory

I have Image cache mechanism in my app. I also need to show local notifications with images. I have a problem. When I try to set UNNotificationAttachment with an image, I get an image from my cache or, if an image doesn't exist, I download it and cache. Then I build a URL to Caches directory, but when I pass this URL to UNNotificationAttachment, I get an error: NSLocalizedDescription=Invalid attachment file URL. What do I make wrong?
if let diskUrlString = UIImageView.sharedImageCache.diskUrlForImageUrl(imageUrl) {
if let diskUrl = URL(string: diskUrlString) {
do {
res = try UNNotificationAttachment(identifier: imageUrlString, url: diskUrl, options: nil)
} catch (let error) {
print("error", error)
// Invalid attachment file URL
}
}
}
func diskUrlForImageUrl(_ imageUrl: URL) -> String? {
let urlRequest = URLRequest(url: imageUrl)
return ImageCache.cacheDirectory.appending("/\(ImageCache.imageCacheKeyFromURLRequest(urlRequest))")
}
static fileprivate var cacheDirectory: String = { () -> String in
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
let res = documentsDirectory.appending("/scAvatars")
let isExist = FileManager.default.fileExists(atPath: res, isDirectory: nil)
if !isExist {
try? FileManager.default.createDirectory(atPath: res, withIntermediateDirectories: true, attributes: nil)
}
return res
}()
I have found that if I add a prefix file:///private to diskUrlString, then URL builds like expected. But I didn't still understand, how to build the url without hardcoding this prefix. So now I can use both cache and UNNotificationAttachment!
The problem here is that you are using a path, not a URL. A path is a string, like "/var/log/foo.log". A URL is semantically more complex than a path. You need a URL that describes the location of the image file on the device file system.
Build a properly constructed URL to the image file and the attachment may work. The attachment may also need a type identifier hint to tell iOS what kind of data is in the file.
You do not have to use urls. You can use image data with UNNotificationAttachment.
Here is a sample code.
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
let imageURL = URL(fileURLWithPath: paths.first!).appendingPathComponent("\(fileName).jpg")
let image = UIImage(contentsOfFile: imageURL.path)
let imageData = image?.pngData()
if let unwrappedImageData = imageData, let attachement = try? UNNotificationAttachment(data: unwrappedImageData, options: nil) {
content.attachments = [attachement]
}

how to delete file from my iphone 's app memory. from file manager ios swift

i am storing my data in file manager in my app. now i want to delete specific data by code so how can i do this?
here is my code which i used for store data
var localURL : String
init()
{
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
localURL = urls.first!.URLByAppendingPathComponent("podcasts").path!
createDirectory(localURL)
}
func downloadShow(slug: String, show: NSDictionary) {
SVProgressHUD.showWithStatus("Downloading...")
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let url = NSURL(string: show["file"] as! String)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error == nil) {
let showFileName = url?.lastPathComponent
let programMP3Path = self.localURL + "/" + slug + "/" + showFileName!
let programDataPath = programMP3Path + ".dat"
data?.writeToFile(programMP3Path, atomically: true)
show.writeToFile(programDataPath, atomically: true)
print("Success")
print(showFileName)
SVProgressHUD.dismiss()
}
else {
// Failure
print("Faulure: \(error)");
}
})
task.resume()
}}
Not sure about session methods. Here's how to delete file in user temp directory, if that helps
let myFileName = "myFile.txt"
var fileManager = NSFileManager()
var tempDirectory = NSTemporaryDirectory()
let filePath = tempDirectory.stringByAppendingPathComponent(myFileName)
var error: NSError?
// also good idea to check before if the file is in the directory
let path = tmpDir.stringByAppendingPathComponent(isFileInDir)
fileManager.removeItemAtPath(path, error: &error)

Play video downloaded through CloudKit as CKAsset - iOS

I'm making an app that records video, uploads it to iCloud using CloudKit with a CKAsset, then downloads the file and plays it in an AVPlayer. This is all written in Swift 2.0
I have gotten the data downloaded, and I think I've been able to reference it but I'm not sure. Data/garbage does print when I convert the URL into an NSData object and print it to the console. The video files gets downloaded as a binary file however. I was able to go to the CloudKit dashboard and download the file and append '.mov' to it, and it opened in Quicktime no problem.
So I think my main issue is that I can't work out how to get the video file to actually play, since the file has no extension. I have tried appending '.mov' to the end with URLByAppendingPathExtension() to no avail. Let me know of any ideas!
Upload Video
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let tempURL = info[UIImagePickerControllerMediaURL] as! NSURL
dismissViewControllerAnimated(true) { () -> Void in
self.uploadVideoToiCloud(tempURL)
print("\n Before Upload: \(tempURL)\n")
}
}
func uploadVideoToiCloud(url: NSURL) {
let videoRecord = CKRecord(recordType: "video", recordID: id)
videoRecord["title"] = "This is the title"
let videoAsset = CKAsset(fileURL: url)
videoRecord["video"] = videoAsset
CKContainer.defaultContainer().privateCloudDatabase.saveRecord(videoRecord) { (record, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error == nil {
print("upload successful")
} else {
print(error!)
}
})
}
}
Download Video
func downloadVideo(id: CKRecordID) {
privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
if error != nil {
print(" Error Fetching Record " + error!.localizedDescription)
} else {
if results != nil {
print("pulled record")
let record = results!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL
print(" After Download: \(self.videoURL!)")
self.videoAsset = AVAsset(URL: self.videoURL!)
self.playVideo()
} else {
print("results Empty")
}
}
}
}
}
The root problem is that AVPlayer expects a file extension, for example .mov, but CKAsset's fileURL property points to a file that lacks an extension. The cleanest solution is to create a hard link, which avoids shuffling megabytes of data around and requires no disk space:
- (NSURL *)videoURL {
return [self createHardLinkToVideoFile];
}
- (NSURL *)createHardLinkToVideoFile {
NSError *err;
if (![self.hardURL checkResourceIsReachableAndReturnError:nil]) {
if (![[NSFileManager defaultManager] linkItemAtURL:self.asset.fileURL toURL:self.hardURL error:&err]) {
// if creating hard link failed it is still possible to create a copy of self.asset.fileURL and return the URL of the copy
}
}
return self.hardURL;
}
- (void)removeHardLinkToVideoFile {
NSError *err;
if ([self.hardURL checkResourceIsReachableAndReturnError:nil]) {
if (![[NSFileManager defaultManager] removeItemAtURL:self.hardURL error:&err]) {
}
}
}
- (NSURL *)hardURL {
return [self.asset.fileURL URLByAppendingPathExtension:#"mov"];
}
Then in the view controller, point AVPlayer to videoURL instead of asset.fileURL.
Solution ended up being that I forgot to specify the filename before I wrote the data to it. I was using URLByAppendingPathExtension and it messed up the URL, ended up using URLByAppendingPathComponent and adding a filename there. Here's the solution that worked for me! Thanks for the comments guys.
func downloadVideo(id: CKRecordID) {
privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
if error != nil {
print(" Error Fetching Record " + error!.localizedDescription)
} else {
if results != nil {
print("pulled record")
let record = results as CKRecord!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL as NSURL!
let videoData = NSData(contentsOfURL: self.videoURL!)
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).URLByAppendingPathComponent("filename.mov", isDirectory: false) //This is where I messed up.
NSFileManager.defaultManager().createFileAtPath(destinationPath.path!, contents:videoData, attributes:nil)
self.videoURL = destinationPath
self.videoAsset = AVURLAsset(URL: self.videoURL!)
self.playVideo()
} else {
print("results Empty")
}
}
}
}
}
Here's the solution for multiple video download from CloudKit. Using this you can store the video on multiple destination and get easily file path
import AVKit
import CloudKit
var assetForVideo = [CKAsset]()
var videoURLForGetVideo = NSURL()
database.perform(queryForVideo, inZoneWith: nil) { [weak self] record, Error in
guard let records = record, Error == nil else {
return
}
DispatchQueue.main.async { [self] in
self?.assetForVideo = records.compactMap({ $0.value(forKey: "video") as? CKAsset })
for (i,dt) in self!.assetForVideo.enumerated(){
self!.videoURLForGetVideo = (dt.fileURL as NSURL?)!
let videoData = NSData(contentsOf: self!.videoURLForGetVideo as URL)
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).appendingPathComponent(self!.assetForVideo.count == i ? "filename\(self!.assetForVideo.count).mov" : "filename\(i+1).mov", isDirectory: false)! as NSURL
FileManager.default.createFile(atPath: destinationPath.path!, contents: videoData as Data?, attributes: nil)
self?.videoURLForGetVideo = destinationPath
self!.videoAssett = AVURLAsset(url: self!.videoURLForGetVideo as URL)
let abc = self!.videoAssett.url
let videoURL = URL(string: "\(abc)")
}
}
}

Swift download with byte-range request

I have allready implemented a download session, now what i wanna do is make it to download only a portion of that file. i know that its possible through the byte-range but im not sure how do i have to do that in swift. any help would be much appreciated. thanks.
#IBAction func btnStartDownload(sender: NSButton) {
let downloadUrl = NSURL(string:"http://www.joomlaworks.net/images/demos/galleries/abstract/7.jpg")
let sessionConfiguration:NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session:NSURLSession = NSURLSession(configuration: sessionConfiguration)
let sessionDownloadTask:NSURLSessionDownloadTask = session.downloadTaskWithURL(downloadUrl!, completionHandler: { (data, response, error) -> Void in
let data = NSData(contentsOfURL: data)
var fileManager:NSFileManager = NSFileManager.defaultManager()
var paths:NSArray = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var documentsDirectory:NSString = paths[0] as NSString
var databasePath:NSString = documentsDirectory.stringByAppendingString("/\(response.suggestedFilename!)")
fileManager.createFileAtPath(databasePath, contents: data , attributes: nil)
NSLog("Database copied to\(databasePath)")
})
sessionDownloadTask.resume()
}

Resources