iTunesLibrary get all music - swift

I'm new on swift 4.
I'm trying to develop a simple mac program to get all music songs from iTunesLibrary. I did sign my code and import iTunesLibrary.framework to the project. But I get an error about iTlib XPC connection error:
2018-05-29 19:51:16.277312+0700 KODE[2325:47137] ITLib received
XPC_ERROR_CONNECTION_INTERRUPTED connection error (can be ignored).
2018-05-29 19:51:16.277410+0700 KODE[2325:47137] ITLib xpc error:
Connection interrupted
2018-05-29 19:51:16.277441+0700 KODE[2325:47072] Assertion failure:
status == noErr (100005)
Here is my code
override func viewDidLoad() {
super.viewDidLoad()
let library: ITLibrary
do {
library = try ITLibrary(apiVersion: "1.0")
} catch {
print("Error occured!")
return
}
let tracks = library.allMediaItems
for track in tracks {
print(track.album.title!)
}
// Do any additional setup after loading the view.
}

If you have a sandboxed app, go to Capabilites/"App Sandbox"/"File Access"/"Music Folder". Change "None" to "Read Only". It helped me. Also app must be properly signed.

Related

Got an error when dragging files using NSEvent. (macOS)

I wanna drag files to my window and then perform actions.
I tried to use snippets below provided in this answer to distinguish whether you're dragging a file or a window.
// In my window controller
class MyWindowController: NSWindowController {
init() {
// Some initialization steps below are omitted
let win = NSWindow(...)
super.init(window: win)
let contentView = DropView(frame: win.frame)
win.contentView?.addSubview(contentView)
registerGlobalMouseEvent()
}
func registerGlobalMouseEvent() {
self.window?.acceptsMouseMovedEvents = true
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// Codes below will cause errors
let pasteBoard = NSPasteboard(name: .drag)
guard let fileNames = pasteBoard.propertyList(forType: .init(rawValue: "NSFilenamesPboardType")) as? NSArray else { return }
let changeCount = pasteBoard.changeCount
if fileNames.count > 0 && lastChangeCount != changeCount {
lastChangeCount = changeCount
// My actions when dragging
}
})
}
}
Then I ran my codes and started dragging, I got three errors:
[sandbox] Failed to get a sandbox extension
[Framework] Failed to issue sandbox extension for /Users/roy/Downloads/test.txt with error 1
[default] Failed to issue sandbox token for URL: 'file:///Users/roy/Downloads/test.txt' with error: 'Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Cannot issue a sandbox extension for file "/Users/roy/Downloads/test.txt": Operation not permitted}'
 
But when I just do
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// My actions
})
, then everything went fine.
 
The first error seems harmless since it didn't prevent my app from running.
The second and the third ones are deadly and directly caused my app to crash.
I wonder if there are any problems in his code? Any useful thoughts would be great! :)
 
You need to know about Bookmarks and Security Scoped URLs when working with sandbox . A dragged URL gives your app process permission just once to read or read/write a “user selected file” depending on how you configure entitlements.
You can save a bookmark (blob of data) to keep access over subsequent sessions as long as the file isn’t updated by another process at which point the bookmark becomes stale and you will need to encourage the user to select the file again.
Handing a URL to another process across an XPC boundary like sharing requires that you own the file so may involve a copy to your sandbox cache.
e.g:
let dragurl = url_of_dragged_file //at this point you have at-least read access
let cachepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last!
let cachedir = URL(fileURLWithPath: cachepath)
let cacheurl = cachedir
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension(dragurl.pathExtension)
try FileManager.default.copyItem(at: dragurl, to: cacheurl)
At this point you have a copy in your local sandbox cache that can be handed off to a share sheet.
So I finally got a solution for this. :)
It appears that it indeed have something to do with the snippets I mentioned above, and here's the correction:
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
let pasteboard = NSPasteboard(name: .drag)
let changeCount = pasteboard.changeCount
if lastChangeCount != changeCount {
lastChangeCount = changeCount
if pasteboard.canReadObject(forClasses: [NSURL.self], options: [:]) {
/// actions
}
}
})
In this way, I got no errors and my codes run perfectly!

requestApplicationPermission userDiscoverability failed in Mac Catalyst

I have ios app using requestApplicationPermission userDiscoverability. Today, I add Mac Catalyst support, but failed: "requestApplicationPermission(.userDiscoverability) failed, error: CloudKit access was denied by user settings".
container.requestApplicationPermission(.userDiscoverability) { [weak self] (status, error) in
guard let self = self else { return }
DispatchQueue.main.async {
if let error = error {
foolPrint("requestApplicationPermission(.userDiscoverability) failed, error: \(error.localizedDescription)")
}
}
}
And I cannot find settings about userDiscoverability in mac settings, where is it?
This iCloud user guide shows how to change these settings:
On iCloud.com, go to Account Settings, then click Manage Apps That Can Look You Up in the Advanced section.
To prevent an app from showing your name and email address to other users, deselect the app’s checkbox in the list.

MetaWear : CLI application on MACOSX

I am attempting to follow the MetaWear guide on starting a sample application, located here . The problem that I am quickly running into is that I am getting unexpected crashes. Here is how my code is structured
:
Lastly, my Podfile contains the following:
platform :osx, '10.12.6'
target 'meta-wear' do
use_frameworks!
pod 'MetaWear', '~> 2.9'
end
When I run the application, I get a Thread exception as follows on line 5 of the first image:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
While I am certainly a new Swift developer ( noob ), I have no idea why I am unable to reproduce their guide.
Xcode: 9.0
macOS Sierra Version 10.12.6 ( This is where I want to run this command line application )
Update after adding an infinite loop
I updated the main.swift class to ahve the following:
import Foundation
let runLoop = RunLoop.current;
let distantFuture = Date.distantFuture;
print("### we are in the create");
let starter = MetaWearStarter();
print("### we are after the create");
while (runLoop.run(mode: RunLoopMode.defaultRunLoopMode, before: distantFuture)){
print("### listening for a metawear device");
}
I created a class called MetaWearStarter.swift as follows:
import Foundation
import MetaWear
class MetaWearStarter : NSObject {
override init() {
super.init();
print("### we are in the init");
startConnection();
}
func startConnection() {
print("##### connection call was made");
let manager = MBLMetaWearManager.shared();
maanger.startScanForMetaWears() { array in
print("### connection scan was complete")
// Hooray! We found a MetaWear board, so stop scanning for more
MBLMetaWearManager.shared().stopScan()
// Connect to the board we found
if let device = array.first {
device.connectAsync().success() { _ in
print("#### we connected to a device");
}.failure() { error in
print("### unable to connect");
}
}
}
}
}
I get the previous error on this line:
let manager = MBLMetaWearManager.shared();
And my output never makes it past that line:
### we are in the create
### we are in the init
##### connection call was made
An infinite loop to keep the runloop running is not a good habit.
Add a completion handler to your class and stop the runloop on completion.
The usual way to handle the run loop in a CLI is this:
import Foundation
import MetaWear
class MetaWearStarter {
let manager = MBLMetaWearManager.shared()
func startConnection(completion: #escaping (String)->()) {
print("##### connection call was made");
manager.startScanForMetaWears() { array in
print("### connection scan was complete")
// Hooray! We found a MetaWear board, so stop scanning for more
manager.stopScan()
// Connect to the board we found
if let device = array.first {
device.connectAsync().success() { _ in
completion("#### we connected to a device")
}.failure() { error in
completion("### unable to connect, error: \(error.localizedDescription)")
}
} else {
completion("#### no device found")
}
}
}
}
let starter = MetaWearStarter()
let runLoop = RunLoop.current
starter.startConnection { (result) in
print(result)
CFRunLoopStop(runLoop.getCFRunLoop())
}
runLoop.run()
exit(EXIT_SUCCESS)

Problems accessing Calendar using EKEventStore on OSX Sierra with Swift 3

This appears very simple, but I've been struggling for several days to get access to the Calendar on OSX. I have switched on the App Sandbox capability, and I've ticked the "Calendar" box in App Data. I have created very simple app with the following view controller class:
import Cocoa
import EventKit
class ViewController: NSViewController {
var eventControl = EKEventStore()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
As you can see, the only lines of code I've added are to import EventKit and to initialise eventControl.
When I run this in debug, I get an error at the eventControl initialisation line
2016-10-28 15:02:00.056521 calendarTest[4105:847101] CoreData: XPC: Unable to load metadata: Error Domain=NSCocoaErrorDomain Code=134070 "An error occurred in the persistent store." UserInfo={Problem=request failed, insufficient permission}
2016-10-28 15:02:00.057742 calendarTest[4105:847101] [error] error: -addPersistentStoreWithType:NSXPCStore configuration:(null) URL:file:///Users/patrickramsden/Library/Calendars/Calendar%20Cache options:{
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
agentOrDaemon = 1;
serviceName = "com.apple.CalendarAgent.database";
} ... returned error Error Domain=NSCocoaErrorDomain Code=134070 "An error occurred in the persistent store." UserInfo={Problem=request failed, insufficient permission} with userInfo dictionary {
Problem = "request failed, insufficient permission";
}
I can't work out how to get the right permissions.
I am using Xcode 8.1 and macOS Sierra 10.12.1
You need to add a usage description to your info.plist. This is a small description of why you need access to the services that is presented to the user.
<key>NSCalendarsUsageDescription</key>
<string>Description of why you need access to the Calendar</string>
Has anyone else figured this out?
I am running into the same issue, however trying to access anything in the event Store returns nil. Even though "access is granted". Such as:
let eventStore = EKEventStore()
switch EKEventStore.authorizationStatus(for: .event) {
case .authorized:
print("Access Granted")
break
case .denied:
print("Access denied")
case .notDetermined:
eventStore.requestAccess(to: .event, completion:
{(granted: Bool, error: Error?) -> Void in
if granted {
print("Access Granted")
} else {
print("Access denied")
}
})
break
default:
print("Case Default")
break
}
print(eventStore.calendars(for: .event))
Getting the same messages: How to prevent EventStore access error on first run
However the access is working correctly once you start the application again after the user grants permission! My app is not sandboxed. Have you set the "Privacy - Calendars Usage Description" key in your plist?

"An error occurred with the `activeEnergyQuery`. The error was: Authorization not determined."

I'm using Apple's demo HealthKit app called ActivityRings. I have set up the bundle identifiers and entitlements correctly. The iOS app and Watch Extension are working and it's recording data seemingly ok. It should be ok as I haven't touched any code.
However console log says, "An error occurred with the activeEnergyQuery. The error was: Authorization not determined."
As you can see in the reporting query and handler assignment Apple has written to print for this error.
I'd like to know what this is for. Is there broken functionality?
// Create a query to report new Active Energy Burned samples to our app.
let activeEnergyQuery = HKAnchoredObjectQuery(type: activeEnergyType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { query, samples, deletedObjects, anchor, error in
if let error = error {
print("An error occurred with the `activeEnergyQuery`. The error was: \(error.localizedDescription)")
return
}
// NOTE: `deletedObjects` are not considered in the handler as there is no way to delete samples from the watch during a workout.
guard let activeEnergySamples = samples as? [HKQuantitySample] else { return }
sampleHandler(activeEnergySamples)
}
// Assign the same handler to process future samples generated while the query is still active.
activeEnergyQuery.updateHandler = { query, samples, deletedObjects, anchor, error in
if let error = error {
print("An error occurred with the `activeEnergyQuery`. The error was: \(error.localizedDescription)")
return
}
// NOTE: `deletedObjects` are not considered in the handler as there is no way to delete samples from the watch during a workout.
guard let activeEnergySamples = samples as? [HKQuantitySample] else { return }
sampleHandler(activeEnergySamples)
}
currentQuery = activeEnergyQuery
healthStore.executeQuery(activeEnergyQuery)
}
func endWorkoutOnDate(endDate: NSDate) {
workoutEndDate = endDate
workoutButton.setTitle("Begin Workout")
activeEnergyBurnedLabel.setText("0.0")
if let query = currentQuery {
healthStore.stopQuery(query)
}
saveWorkout()
}
requestAuthorizationToShareTypes function
override func willActivate() {
// This method is called when watch view controller is about to be visible to user.
super.willActivate()
// Only proceed if health data is available.
guard HKHealthStore.isHealthDataAvailable() else { return }
// We need to be able to write workouts, so they display as a standalone workout in the Activity app on iPhone.
// We also need to be able to write Active Energy Burned to write samples to HealthKit to later associating with our app.
let typesToShare = Set([
HKObjectType.workoutType(),
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)!])
let typesToRead = Set([
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)!])
healthStore.requestAuthorizationToShareTypes(typesToShare, readTypes: typesToRead) { success, error in
if let error = error where !success {
print("You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: \(error.localizedDescription). If you're using a simulator, try it on a device.")
}
}
}
AppDelegate.swift
import UIKit
import HealthKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let healthStore: HKHealthStore = HKHealthStore()
func applicationShouldRequestHealthAuthorization(application: UIApplication) {
healthStore.handleAuthorizationForExtensionWithCompletion { success, error in
if let error = error where !success {
print("You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: \(error.localizedDescription). If you're using a simulator, try it on a device.")
}
}
}
}
Have you setup your iOS app to handle the healthkit authorization from your watch app? When you request permission to use healthkit types from your Apple Watch, a permission dialog shows up on your iOS app. But, you need to tell your iOS app that you are expecting your apple watch to request it. You do this with the following code in your AppDelegate file:
func applicationShouldRequestHealthAuthorization(application: UIApplication) {
let healthStore = HKHealthStore()
healthStore.handleAuthorizationForExtensionWithCompletion { (success, error) -> Void in
//...
}
}
Note that data can get sent directly from the watch's sensors (like heart rate and calories burned) to healthkit without needing permission from your app. It sounds like your permission errors are because you are trying to read the data (which you don't have permission to do yet).
Your app needs to request authorization to read and write active energy samples. Until the user has chosen whether to authorize your app, authorization will be "not determined". See the HKHealthStore documentation for more information about requesting authorization with requestAuthorizationToShareTypes:readTypes:completion:.