How do I get device id in Apple Cocoa application with swift 4.2?
You can get the Hardware UUID with IOKit
func hardwareUUID() -> String?
{
let matchingDict = IOServiceMatching("IOPlatformExpertDevice")
let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict)
defer{ IOObjectRelease(platformExpert) }
guard platformExpert != 0 else { return nil }
return IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformUUIDKey as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? String
}
Related
I'm having a project where I have to write automation for Apple Watch & iPhone app. I'm forced to use XCUITest with Swift because Appium is not yet supporting WatchOS as a testing target.
In my tests, at some points, I have to communicate with an external device via BLE. I wanted to use the CoreBluetooth framework, but I got no luck with that. I have a working CoreBT code that I've used to create a simple BLE chat app, but for some reason, that same code is not working when called from the UI test.
The main problem is that I'm not able to get CBCentralManager in a powered state:
[CoreBluetooth] API MISUSE: <CBCentralManager: 0x28175ce00> can only accept this command while in the powered on state
Later I checked the BT authorization state inside the test with cbCentralManager.authorization == .notDetermined, and it confirmed that authorization is not confirmed. That might be a problem why CBCentralManager is not powering up, but I'm not sure how to resolve it. The app I'm testing is able to use BT without any issues (has all permissions).
Is it even possible to use CoreBluetooth from UITests??
This is the test class code:
import CoreBluetooth
import XCTest
let peripheralName = "MY-BLE-DEVICE-NAME"
let service_First = CBUUID(string: "0000ffe0-0000-1000-8000-00805f9b34fb")
let readCharacteristic = CBUUID(string: "0000ffe1-0000-1000-8000-00805f9b34fb")
let writeCharacteristic = CBUUID(string: "0000ffe1-0000-1000-8000-00805f9b34fb")
var ble_characteristic: CBCharacteristic?
var ble_perip: CBPeripheral?
class myBLERemoteUITests : XCTestCase {
var cbCentralManager : CBCentralManager!
func wait(timeout: TimeInterval){
let exp = expectation(description: "Wait for X seconds")
let result = XCTWaiter.wait(for: [exp], timeout: timeout)
print("LOG - Timer started for " + String(timeout) + " seconds...")
if result == XCTWaiter.Result.timedOut {
print("LOG - Timer stopped after " + String(timeout) + " seconds...")
}else {
XCTFail("Delay interrupted")
}
}
func test_someBLEtest() throws {
let app = XCUIApplication()
app.launch()
// MARK: Some UI automation steps
app.buttons["Get Started"].tap()
let tablesQuery2 = app.tables
let shoeImage = tablesQuery2.cells["ItemA"].images["item"]
shoeImage.tap()
let shoe2 = tablesQuery2.cells["ItemB"].images["item"]
shoe2.tap()
wait(timeout: 10)
app.buttons["Finish"].tap()
// MARK: Part where I need to communicate with BLE device
// Initialize CBCentralManager
cbCentralManager = CBCentralManager.init(delegate: self, queue: nil) // --> getting API MISUSE mentioned above
wait(timeout: 10)
cbCentralManager = CBCentralManager.init(delegate: self, queue: nil) // --> getting API MISUSE mentioned above
wait(timeout: 10)
cbCentralManager = CBCentralManager.init() // --> getting [CoreBluetooth] XPC connection invalid
// MARK: I check CBCentral Manager Authorization state
if (cbCentralManager.authorization == .allowedAlways){
print("allowed")
}else if (cbCentralManager.authorization == .notDetermined){
print("not determined") // --> I get that authorization is not determined
}
}
}
// MARK: Over here I have all needed CoreBluetooth callback functions:
extension myBLERemoteUITests : CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let services = peripheral.services {
//discover characteristics of services
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let charac = service.characteristics {
for characteristic in charac {
peripheral.setNotifyValue(true, for: characteristic)
if characteristic.uuid == writeCharacteristic {
ble_characteristic = characteristic
}
for newChar: CBCharacteristic in service.characteristics!{
peripheral.readValue(for: newChar)
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid == readCharacteristic {
print("Read Value : \(characteristic)")
}
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic.uuid == writeCharacteristic {
print("WRITE VALUE : \(characteristic)")
}
}
}
extension myBLERemoteUITests : CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
central.scanForPeripherals(withServices: nil, options: nil)
print("Scanning...")
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard peripheral.name != nil else {return}
if peripheral.name! == peripheralName {
print("BLE Device Found!")
//stopScan
cbCentralManager.stopScan()
//connect
cbCentralManager.connect(peripheral, options: nil)
ble_perip = peripheral
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected : \(peripheral.name ?? "No Name")")
peripheral.discoverServices([service_First])
//discover all service
//peripheral.discoverServices(nil)
peripheral.delegate = self
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected : \(peripheral.name ?? "No Name")")
cbCentralManager.scanForPeripherals(withServices: nil, options: nil)
}
}
I submitted my IOS app to app review, and the review says it keeps crashing. Seems like there is a problem with my GeoFire function. I am using it to look for other app users in the area using this function. I load it in ViewDidLoad. It works fine on testflight though. I tried symbolicating the crash report that they sent me (with no luck). However, the report says there is a SIGTRAP exception type and a termination reason as SIGNAL 5. I submitted it using Xcode IOS 12.5, but tested it on iPhones with IOS 15 and it was fine. Not sure why it only crashes on app review. I was wondering if you could let me know if there's something wrong with my code leading to this crash:
func observeGeoFire() {
geoFireRef = Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("user_locations")
geoFire = GeoFire(firebaseRef: geoFireRef!)
let userLat = UserDefaults.standard.value(forKey: "current_latitude") as! String
let userLong = UserDefaults.standard.value(forKey: "current_longitude") as! String
let location:CLLocation = CLLocation(latitude: CLLocationDegrees(Double(userLat)!), longitude: CLLocationDegrees(Double(userLong)!))
Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("users").child((user?.uid)!).observeSingleEvent(of: .value, with: { (DataSnapshot) in
let Rad = self.rad ?? 0.0
self.myQuery = self.geoFire?.query(at: location, withRadius: Rad)
self.myQuery?.observe(GFEventType.keyEntered, with: { (key, location) in
if key != Auth.auth().currentUser?.uid {
Database.database().reference(fromURL: "https://yala-2018.firebaseio.com/").child("users").child(key).observeSingleEvent(of: .value, with: { (DataSnapshot) in
if let dictionary = DataSnapshot.value as? [String: AnyObject] {
let user = Users()
user.id = DataSnapshot.key
user.name = dictionary["name"] as? String
user.eventsAttended = dictionary["Events Attended"] as? Int
user.eventsCreated = dictionary["Events Created"] as? Int
user.profileImageUrl = dictionary["profilePicUrl"] as? String
user.education = dictionary["education"] as? String
user.occupation = dictionary["Occupation"] as? String
user.origin = dictionary["origin"] as? String
user.relationshipStatus = dictionary["relationship status"] as? String
user.profileImageUrl = dictionary["profilePicUrl"] as? String
if user.name != nil && user.profileImageUrl != nil {
self.users.append(user)
} else {
print("done")
}
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
} else {
print("cannot retrieve user")
}
})
}
})
})
waiting.stopAnimating()
}
Previous version of AudioKit had AKMicrophone.setDevice(_:), but since AKMicrophone was removed in v5, what is the correct way to get input from a device other than the default (on macOS)?
Here's what I've tried so far (map is called with a valid device ID, of that I'm sure):
func map(in: AudioDeviceID) {
let engine = AudioEngine()
let inUnit = engine.avEngine.inputNode.audioUnit!
setDevice(for: inUnit, to: `in`)
engine.output = engine.input
try! engine.start()
}
private func setDevice(for unit: AudioUnit, to id: AudioDeviceID) {
var deviceId = id;
let err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, UInt32(MemoryLayout<AudioDeviceID>.size))
if (err != noErr) {
print(err)
assert(false)
}
}
But when it calls engine.start() it crashes with:
2021-02-12 01:02:27.304545-0600 Roundabout[24616:587679] [avae] AVAEInternal.h:88 required condition is false: [AVAudioEngineGraph.mm:1408:Initialize: (IsFormatSampleRateAndChannelCountValid(outputHWFormat))]
Removing the setDevice call works, but then it's just passing the default microphone through, which is not what I want.
I'm trying to make an application that communicates with a USB device about the same way I use the screen command on Terminal.
To make my question easier to understand, This is what I normally do in Terminal :
command :
ls /dev/tty.usb*
returns :
/dev/tty.usbmodem1411 /dev/tty.usbmodem1451
Next, I call :
screen /dev/tty.usbmodem1411
After this, I can send commands to the device (type in 'U' for example, get a response)
I'm trying to do this from Xcode now.
Using IOKit, I've managed to execute what is equivalent to the first command that returns the list of usb ports :
/dev/tty.usbmodem1411 /dev/tty.usbmodem1451
This is the code :
#IBAction func testPressed(sender: AnyObject) {
var portIterator: io_iterator_t = 0
let kernResult = findSerialDevices(kIOSerialBSDModemType, serialPortIterator: &portIterator)
if kernResult == KERN_SUCCESS {
printSerialPaths(portIterator)
}
}
func findSerialDevices(deviceType: String, inout serialPortIterator: io_iterator_t ) -> kern_return_t {
var result: kern_return_t = KERN_FAILURE
var classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue).takeUnretainedValue()
var classesToMatchDict = (classesToMatch as NSDictionary) as Dictionary<String, AnyObject>
classesToMatchDict[kIOSerialBSDTypeKey] = deviceType
let classesToMatchCFDictRef = (classesToMatchDict as NSDictionary) as CFDictionaryRef
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatchCFDictRef, &serialPortIterator);
return result
}
func printSerialPaths(portIterator: io_iterator_t) {
var serialService: io_object_t
do {
serialService = IOIteratorNext(portIterator)
if (serialService != 0) {
let key: CFString! = "IOCalloutDevice"
let bsdPathAsCFtring: AnyObject? = IORegistryEntryCreateCFProperty(serialService, key, kCFAllocatorDefault, 0).takeUnretainedValue()
var bsdPath = bsdPathAsCFtring as String?
if let path = bsdPath {
println(path)
}
}
} while serialService != 0;
}
}
Now, even after reading Apple's IOKit manual, I can't move forward.
How can I start sending commands using IOKit ?
See Apple Performing Serial I/O sample project.
I couldn't find any info about getting user's location info in swift and xcode 6
I tried
var fbcity = user.objectForKey("location")
var fbcountry = user.objectForKey("country")
But didn't work.
Any idea how to achieve this ?
Perhaps you could supply us with a little more information, e.g. which Facebook SDK you are using and what parameters FBSDKGraphRequest has to return user. Note that there is no specific information about country, the location field in the user node when your send a graph request for the user profile. It will return the subfields: id and name, where name is
With the latest Facebook iOS SDK 4.0 you can do something like:
override func viewDidLoad() {
super.viewDidLoad()
self.loginView.delegate = self
if FBSDKAccessToken.currentAccessToken() != nil {
fetchUserData()
} else {
loginView.readPermissions = ["public_profile", "email", "user_friends"]
}
}
func fetchUserData() {
let graphRequest: FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: nil)
graphRequest.startWithCompletionHandler({ (connection, result, error) -> Void in
if error != nil {
// Process error
println("Error: \(error)")
} else {
let location: NSDictionary! = result.valueForKey("location") as NSDictionary
let city: NSString = location.valueForKey("name") as NSString
}
})
}
More detailed info can be found on Facebook Graph API User page.