I am creating an album in the users photo library, now I want to save a video there. I am saving the video to a file using:
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let filePath = documentsURL.URLByAppendingPathComponent("video")
Now I want to take the video, and save it to an album. I've found lots on saving to the camera roll, but nothing on saving to an album. Can it be done, and if so, how?
Assuming you have a PHAssetCollection specifying the album, you can use this PHAssetCollection extension:
extension PHAssetCollection {
private func isCameraRollAlbum() -> Bool
{
let query = PHAssetCollection.fetchAssetCollections(with: .smartAlbum,
subtype: .smartAlbumUserLibrary,
options: nil)
let result: PHAssetCollection? = query.firstObject
return self == result
}
func save(videoURL: URL, completion: #escaping (URL?, String?) -> ()) {
let isCameraRoll = isCameraRollAlbum()
DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: .now()) {
PHPhotoLibrary.shared().performChanges({
if let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL) {
if isCameraRoll == false, let placeholder = assetRequest.placeholderForCreatedAsset {
let albumChangeRequest = PHAssetCollectionChangeRequest(for: self)
albumChangeRequest?.addAssets([placeholder] as NSArray)
}
}
}, completionHandler: { (success, error) in
if success == false {
completion(nil, error?.localizedDescription)
}
else {
completion(videoURL, nil)
}
})
}
}
}
Remarks:
Method 'isCameraRollAlbum' was defined because it was found that the use of placeholders for the whole photo album doesn't work, and you only need to use
PHAssetChangeRequest.creationRequestForAssetFromVideo
to save a video to the whole photo library.
Using a background thread is not necessary.
Example usage, it is assumed a video named 'Video.mov' is in the Documents directory of the app. This will save it to the 'Camera Roll' album but a PHAssetCollection for any album can be specified:
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let videoURL = docsurl.appendingPathComponent("Video.mov")
let fetchResult = PHAssetCollection.fetchAssetCollections(with:.smartAlbum,subtype:.smartAlbumUserLibrary,options: nil)
if let allMediaAlbum = fetchResult.firstObject {
allMediaAlbum.save(videoURL: videoURL) { (url, message) in
print("message = \(String(describing: message))")
}
}
For example, you can use this extension to obtain the PHAssetCollection for an album with a given name 'title':
class func getAlbum(title: String, completionHandler: #escaping (PHAssetCollection?) -> ()) {
DispatchQueue.global(qos: .userInteractive).asyncAfter(deadline: .now()) {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", title)
let collections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let album = collections.firstObject {
completionHandler(album)
} else {
completionHandler(nil)
}
}
}
Example usage, saving video 'Video.mov' to album named 'My Umbrella':
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let albumName = "My Umbrella"
let videoURL = docsurl.appendingPathComponent("Video.mov")
PHAssetCollection.getAlbum(title: albumName) { (album) in
if let album = album {
album.save(videoURL: videoURL, completion: { (url, error) in
if let url = url {
print("Video '\(url.lastPathComponent) saved to '\(albumName)'")
}
else {
print("Error: \(String(describing: error))")
}
})
}
}
(Keep in mind that the photos library can have multiple albums by the same name.)
Related
i am developing an employee management app thats why i need to save profile picture against employee id or email .In firebase database what is the process and how can i design database through source code.In swift 3,xcode 8.3.2,ios 10.
You need to store the profile Image on the firebase storage,
after that imageURL will be retrieved. After the imageURL is retrieved you need to save it on the firebase database as a child of the userId.
Refer the code below
func handleRegister() {
guard let email = self.emailTextField.text, let password = self.passwordTextField.text, let name = self.nameTextField.text else {
print("Form is not valid")
return
}
Auth.auth().createUser(withEmail: email, password: password) { (user: User?, error) in
if error != nil {
print(error!)
return
}
guard let uid = user?.uid else {
return
}
//success
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("\(imageName).png")
if let uploadData = UIImageJPEGRepresentation(self.profileImageView.image!, 0.1) {
storageRef.putData(uploadData, metadata: nil, completion:
{ (metadata, error) in
if error != nil {
print(error!)
return
}
print(metadata!)
if let progileImageURL = metadata?.downloadURL()?.absoluteString {
let values = ["name": name, "email": email, "profileImageUrl": progileImageURL]
self.registerUserIntoDatabaseWithUID(uid: uid, values: values as [String : AnyObject])
}
})
}
}
}
func registerUserIntoDatabaseWithUID(uid: String, values: [String: AnyObject]) {
let ref = Database.database().reference()
let userRef = ref.child("users").child(uid)
userRef.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err!)
return
}
print("Saved user successfully into Firebase db")
self.messagesController1?.checkIfUseLoggedin()
self.dismiss(animated: true, completion: nil)
})
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage {
selectedImageFromPicker = editedImage
print(editedImage)
}
else if let orignalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage {
selectedImageFromPicker = orignalImage
print(orignalImage)
}
if let selectedImage = selectedImageFromPicker {
self.profileImageView.image = selectedImage
}
self.dismiss(animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("picker cancled")
self.dismiss(animated: true, completion: nil)
}
I'm using QBImagePicker. I tried to get image file name, but it's very difficult. What can I do for that? I don't know it.
func qb_imagePickerController(_ imagePickerController: QBImagePickerController!, didFinishPickingAssets assets: [Any]!) {
let requestOptions = PHImageRequestOptions()
requestOptions.resizeMode = PHImageRequestOptionsResizeMode.exact
requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
// this one is key
requestOptions.isSynchronous = true
for asset in assets {
if ((asset as AnyObject).mediaType == PHAssetMediaType.image) {
PHImageManager.default().requestImage(for: asset as! PHAsset, targetSize: PHImageManagerMaximumSize, contentMode: PHImageContentMode.default, options: requestOptions, resultHandler: {
(pickedImage, info) in
self.selectImage.image = self.resizeImage(getImageView: self.selectImage, originImage: pickedImage!)
})
}
}
imagePickerController.dismiss(animated: true, completion: nil)
}
Try this
if let fileName = Asset.value(forKey: "filename") as? String{
print(fileName)
}
let originalName = PHAssetResource.assetResources(for: asset).first?.originalFilename
print("original File name \(originalName)")
I have used the below implementation to play a video with cookies content from the server, but it shows play icon with cross line. I have refer the link and do following implementation in swift. but I didn't get any output :(
func showVideo(url: String) {
let videoURL = NSURL(string: url)
var cookiesArray = [HTTPCookie]()
guard let cookieArray = UserDefaults.standard.array(forKey:
Constants.Object.kCookie) as? [[HTTPCookiePropertyKey: Any]] else {
return }
for cookieProperties in cookieArray {
if let cookie = HTTPCookie(properties: cookieProperties) {
cookiesArray.append(cookie)
}
}
let cookieArrayOptions = [AVURLAssetHTTPCookiesKey: cookiesArray]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}
Please help me on that, what is wrong in that implementation.
Thanks in advance! :)
After going through so many ways finally I have got the solution which worked for me :
func showVideo(url: String) {
let videoURL = NSURL(string: url)
let cookiesArray = HTTPCookieStorage.shared.cookies! //Stored Cookies of your request
let values = HTTPCookie.requestHeaderFields(with: cookiesArray)// Returns a dictionary of header fields corresponding to a provided array of cookies.ex.["Cookie":"your cookies values"]
let cookieArrayOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}
I am fetching user's information like his name,phone number and email id from contacts.But it is only showing first contact number.IF a person has more than one contact number,it didnt show that second number.Can someone help?I am using this function
where EVContactProtocol is part of Library
func didChooseContacts(_ contacts: [EVContactProtocol]?) {
var conlist : String = ""
if let cons = contacts {
for con in cons {
if let fullname = con.fullname(),let email1 = con.email , let phoneNumber = con.phone {
conlist += fullname + "\n"
print("Full Name: ",fullname)
print("Email: ",email1)
print("Phone Number: ",phoneNumber)
}
}
self.textView?.text = conlist
} else {
print("I got nothing")
}
let _ = self.navigationController?.popViewController(animated: true)
}
You should try this:
import Contacts
class ViewController: UIViewController
{
lazy var contacts: [CNContact] =
{
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey] as [Any]
// Get all the containers
var allContainers: [CNContainer] = []
do
{
allContainers = try contactStore.containers(matching: nil)
}
catch
{
print("Error fetching containers")
}
var results: [CNContact] = []
// Iterate all containers and append their contacts to our results array
for container in allContainers
{
let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
do
{
let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
results.append(contentsOf: containerResults)
}
catch
{
print("Error fetching results for container")
}
}
return results
}()
override func viewDidLoad()
{
super.viewDidLoad()
print(contacts[0].givenName)
print(contacts[0].phoneNumbers)
print(contacts[0].emailAddresses)
print(contacts)
}
}
I am trying to use youtube api in ios swift, and following this tutorial
http://www.appcoda.com/youtube-api-ios-tutorial/
HTTP Status Code = 403
Error while loading channel details: nil
I'm using swift 3
var urlString = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=\(textField.text)&type=\(type)&key=\(apiKey)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Get the results.
performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
// Convert the JSON data to a dictionary object.
do {
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, AnyObject>
// Get all search result items ("items" array).
let items: Array<Dictionary<String, AnyObject>> = resultsDict["items"] as! Array<Dictionary<String, AnyObject>>
// Loop through all search results and keep just the necessary data.
for i in 0 ..< items.count {
let snippetDict = items[i]["snippet"] as! Dictionary<String, AnyObject>
// Gather the proper data depending on whether we're searching for channels or for videos.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
// Keep the channel ID.
self.desiredChannelsArray.append(snippetDict["channelId"] as! String)
}
else {
// Create a new dictionary to store the video details.
var videoDetailsDict = Dictionary<String, AnyObject>()
videoDetailsDict["title"] = snippetDict["title"]
videoDetailsDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<String, AnyObject>)["default"] as! Dictionary<String, AnyObject>)["url"]
videoDetailsDict["videoID"] = (items[i]["id"] as! Dictionary<String, AnyObject>)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
self.videosArray.append(videoDetailsDict)
// Reload the tableview.
self.tblVideos.reloadData()
}
}
} catch {
print(error)
}
// Call the getChannelDetails(…) function to fetch the channels.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
self.getChannelDetails(true)
}
}
else {
print("HTTP Status Code = \(HTTPStatusCode)")
print("Error while loading channel videos: \(error)")
}
// Hide the activity indicator.
self.viewWait.isHidden = true
})
return true
}
// MARK: Custom method implementation
func performGetRequest(_ targetURL: URL!, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int, _ error: NSError?) -> Void) {
// let request = NSMutableURLRequest(url: targetURL)
// request.httpMethod = "GET"
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
/* let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void)*/
/* let task = session.dataTask(with: request, completionHandler: ({ (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data as Data?, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void))*/
let task = session.dataTask(with: request) { data, response, error in DispatchQueue.main.async { completion(data, (response as! HTTPURLResponse).statusCode, error as? NSError) } }
task.resume()
}
First of all the JSON dictionary representation in Swift 3 is [String:Any] (aka Dictionary<String,Any>)
Second of all in Swift 3 all parameter labels in closures have been removed
func performGetRequest(_ targetURL: URL, completion: #escaping (Data?, Int, NSError?) -> Void) {
Do not use implicit unwrapped optionals for method parameter types. Either use regular optional (?) or non-optional.
Error 403 means Forbidden Access. Make sure you have the correct apiKey from google/youtube developer.
I also used the appcoda youtube api tutorial (which is in Swift 2 I think) and this is a working version of mine for swift 3.
func getVideosForChannelAtIndex() {
let urlString = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=\(playlistID)&maxResults=\(maxResults)&key=\(apiKey)"
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Fetch the playlist from Google.
performGetRequest(targetURL!) { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
do {
self.videos = []
// Convert the JSON data into a dictionary.
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<AnyHashable, Any>
// Get all playlist items ("items" array).
let items:Array<Dictionary<AnyHashable, Any>> = resultsDict["items"] as! Array<Dictionary<AnyHashable, Any>>
// Use a loop to go through all video items.
// for var i=0; i<items.count; ++i
for i in 0 ..< items.count {
let playlistSnippetDict = (items[i] as Dictionary<AnyHashable, Any>)["snippet"] as! Dictionary<AnyHashable, Any>
let video = Video()
video.title = playlistSnippetDict["title"] as? String
// video.thumbnail =
video.videoId = (playlistSnippetDict["resourceId"] as? Dictionary<AnyHashable, Any>)?["videoId"] as? String
guard let thumbnail = ((playlistSnippetDict["thumbnails"] as? Dictionary<AnyHashable, Any>)?["high"] as? Dictionary<AnyHashable, Any>)?["url"] as? String else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
guard let url:URL? = URL(string: thumbnail), let data:Data? = try? Data(contentsOf: url!) else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
if let dataImage = data {
video.thumbnail = UIImage(data: dataImage)
} else {
video.thumbnail = UIImage(named: "Icon1024x1024")
}
self.videos.append(video)
// Reload the tableview.
self.tblVideos.reloadData()
}
} catch {
print("json error: \(error)")
}
} else {
print("")
print("HTTP Status Code = \(HTTPStatusCode)")
print("")
//Show alertDialog here with Error
print("Error while loading videos: \(error?.localizedDescription)")
let alert = UIAlertView(title: "Oops!", message: error?.localizedDescription, delegate: self, cancelButtonTitle: "OK")
alert.show()
}
// Hide the activity indicator.
self.viewWait.isHidden = true
}
}
This is for the performGetRequest
func performGetRequest(_ targetURL: URL, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int?, _ error: Error?) -> Void) {
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
completion(data, (response as? HTTPURLResponse)?.statusCode, error)
})
}
task.resume()
}