Why aren't my Characteristic appearing in BLE advertisement Swift - iphone

I want to advertise some characteristics from an iPhone acting as a peripheral, but although the service seems to contain the characteristics they don't show up when you look at it with a BLE scanner, the service works fine and displays the localNameKey.
thanks
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBPeripheralManagerDelegate{
var peripheralManager: CBPeripheralManager!
let myCustomServiceUUID: CBUUID = CBUUID(string: "B5893BC9-63AB-42A5-BB33-EEAE686BED1D")
let myCustomCharacteristic: CBUUID = CBUUID(string: "9BA41369-C5B7-456B-B4E3-BB0A8DFF3A95")
let myCustomCharacteristic2: CBUUID = CBUUID(string: "9BA41369-C5B7-456B-B4E3-BB0A8DFF3A85")
var myService: CBMutableService!
var myCharacteristics: CBMutableCharacteristic!
var myCharacteristics2: CBMutableCharacteristic!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
myService = CBMutableService(type: myCustomServiceUUID, primary: true)
myCharacteristics = CBMutableCharacteristic(type: myCustomCharacteristic, properties: CBCharacteristicProperties.Broadcast, value: nil, permissions: CBAttributePermissions.Readable)
myCharacteristics2 = CBMutableCharacteristic(type: myCustomCharacteristic2, properties: CBCharacteristicProperties.Broadcast, value: nil, permissions: CBAttributePermissions.Readable)
myService.characteristics = [myCharacteristics, myCharacteristics2]
peripheralManager.addService(myService)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager) {
if peripheral.state == CBPeripheralManagerState.PoweredOn {
let dataTobeAdvetised :[String: AnyObject!] = [CBAdvertisementDataServiceUUIDsKey: [myService.UUID], CBAdvertisementDataLocalNameKey: "MY Device"]
self.peripheralManager.startAdvertising(dataTobeAdvetised)
print(myService)
print("It should be working!........")
} else if peripheral.state == CBPeripheralManagerState.PoweredOff {
self.peripheralManager.stopAdvertising()
}
}
}

You aren't permitted to use CBCharacteristic.broadcast property value.
From the documentation -
CBCharacteristicPropertyBroadcast
The characteristic’s value can be broadcast using a characteristic
configuration descriptor.
This property is not allowed for local characteristics published via
the addService: method of the CBPeripheralManager class. This means
that you cannot use this property when you initialize a new
CBMutableCharacteristic object via the
initWithType:properties:value:permissions: method of the
CBMutableCharacteristic class.
You should use some combination of CBCharacteristicPropertyRead, CBCharacteristicPropertyWriteWithoutResponse and CBCharacteristicPropertyWrite depending on your requirements.

Old question, but hopefully this will help somebody else. I was struggling with the same issue, but for me there was no didAddService callback. Turns out GATT initialisation should be after the peripheral state has changed to PoweredOn.
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager) {
if peripheral.state == CBPeripheralManagerState.PoweredOn {
//Do initialisation and then start advertising.
}
}

Related

Basic Sinch Sample in Swift - but no Sound

first of all thank you for reading my lines.
For an idea I'm currently trying to dive into the Swift world (I only have very basic programming knowledge - no Objective C knowledge
).
I tried to set up the following lines to create a very basic app-to-app sample in Sinch. After my code I let you know what the issues are.
import UIKit
import Sinch
var appKey = "APP_KEY_FROM_MY_ACCOUNT"
var hostname = "clientapi.sinch.com"
var secret = "SECRET_FROM_MY_ACCOUNT"
class CViewController: UIViewController, SINCallClientDelegate, SINCallDelegate, SINClientDelegate {
var client: SINClient?
var call: SINCall?
var audio: SINAudioController?
//Text field in the main storyboard
#IBOutlet weak var userNameSepp: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.initSinchClient()
}
//initialize and start the client as a fixed "userA"
func initSinchClient() {
client = Sinch.client(withApplicationKey: appKey, applicationSecret: secret, environmentHost: hostname, userId: "userB")
client?.call().delegate = self
client?.delegate = self
client?.startListeningOnActiveConnection()
client?.setSupportCalling(true)
client?.start()
}
//Did the Client start?
func clientDidStart(_ client: SINClient!) {
print("Hello")
}
//Did the Client fail?
func clientDidFail(_ client: SINClient!, error: Error!) {
print("Good Bye")
}
//Call Button in the main.storyboard ... if call==nil do the call ... else hangup and set call to nil
//the background color changes are my "debugging" :D
#IBAction func callSepp(_ sender: Any) {
if call == nil{
call = client?.call()?.callUser(withId: userNameSepp.text)
//for testing I change to callPhoneNumber("+46000000000").
// the phone call progresses (but I hear nothing),
// the phonecall gets established (but I hear nothing)
// and the phonecall gets ended (but of course I hear nothing)
self.view.backgroundColor = UIColor.red
call?.delegate = self
audio = client?.audioController()
}
else{
call?.hangup()
self.view.backgroundColor = UIColor.blue
call = nil
}
}
func callDidProgress(_ call: SINCall?) {
self.view.backgroundColor = UIColor.green
client?.audioController().startPlayingSoundFile("/LONG_PATH/ringback.wav", loop: true)
print("Call in Progress")
}
//I know that this works but I don't hear anything
func callDidEstablish(_ call: SINCall!) {
client?.audioController().stopPlayingSoundFile()
print("Call did Establish")
}
func callDidEnd(_ call: SINCall!) {
print("Call did end")
}
// this works fine
#IBAction func hangUpSepp(_ sender: Any) {
call?.hangup()
self.view.backgroundColor = UIColor.red
call = nil
}
// i work in a "sub view controller" - so i navigate here back to the main view controller
#IBAction func goBackMain(_ sender: Any) {
call?.hangup()
dismiss(animated: true, completion: nil)
client?.stopListeningOnActiveConnection()
client?.terminateGracefully()
client = nil
}
}
So I can call my private phone number or if I change to callUser I can call another app but I don't hear anything. What do I miss? It must have to do with the SINAudioController and the client's method audioController() but I don't know what I'm doing wrong. Thank you for your help.

How to pass potential error between methods

I'm trying to wrap Core Bluetooth Peripheral methods for use in React Native. It's a counterpart for already finished android code, so the API is set.
When I'm calling CBPeripheralManager.addService, I need to fulfill or reject a promise, handed from the javascript side.
The problem is, Core Bluetooth doesn't offer a callback for the method, it seems to expect private func peripheralManager(_ peripheral: CBPeripheralManager, didAddService service: CBService, error: Error?)
I'm new to iOS and Swift so this behavior seems strange to me. Any ideas how can I wrap the function so I can handle the error reporting properly?
Thanks
class BLE: NSObject, CBPeripheralManagerDelegate {
var advertising: Bool = false
var servicesMap = Dictionary<String, CBMutableService>()
var manager: CBPeripheralManager!
override init() {
super.init()
manager = CBPeripheralManager(delegate: self, queue: nil, options: nil)
}
func addService(promise, serviceUUID) {
let serviceUUID = CBUUID(string: uuid)
let service = CBMutableService(type: serviceUUID, primary: true)
manager.add(service)
}
private func peripheralManager(_ peripheral: CBPeripheralManager, didAddService service: CBService, error: Error?) {
if let error = error {
// this should reject the addService promise
return
}
// this should fulfill the promise
}
}
It's unclear what the type of promise is, but you'll need to store it somewhere, and then fulfill it later. For example, you might add a property:
var pendingServices: [CBUUID: Promise] = [:]
(I don't know what you're promise type really is here)
Then you'd store it in addService:
assert(pendingServices[serviceUUID] == nil)
pendingServices[serviceUUID] = promise
And later in (the correct; see my comment) delegate method, you'd deal with it:
if let promise = pendingServices.removeValue(forKey: service.uuid) {
promise.fulfill() // Or whatever you do with it
}

Losing reference to variable while using SocketIO in swift 4

I'm new to Swift and have always been a bit messy when it comes to developing for iOS so bear with me.
So in my AppDelegate I have a variable like such
var manager = Manager()
and in didFinishLaunchingWithOptions I've got
let controller = ChatRoomViewController()
self.manager.delegate = controller
self.manager.setup()
self.manager.attemptToIdentify(user:username);
In the Manager I've got
var connectionManager = SocketManager(socketURL: URL(string: "http://0.0.0.0:8080")!)
var usersName = ""
var socket:SocketIOClient!
func setup(){
connectionManager.reconnects = true
socket = connectionManager.defaultSocket;
self.setSocketEvents();
socket.connect();
}
This works and I'm able to open up a socket which displays the username on the node.js server. Now when I navigate away from the main view to the chat controller and call
appDelegate.manager.attemptMessage(msg: message);
the console tells me that I'm no longer connected. Best I can tell, I'm losing the reference to one of my variables.
I don't think you should declare your variable in the AppDelegate.
I am using Socket.IO too in one of my app and I prefer use it from a shared instance class. I don't know if you are familar with it, but it is a common architecture in iOS development.
It is based on a singleton instance and allows you to keep instance of variables in memory during all the life of the app.
For you case, you can do the following for example:
private let _managerSharedInstance = Manager()
class Manager() {
private var connectionManager = SocketManager(socketURL: URL(string: "http://0.0.0.0:8080")!)
private var usersName = ""
private var socket:SocketIOClient!
var delegate: UIViewController?
class var shared: Manager {
return _managerSharedInstance
}
init() {
connectionManager.reconnects = true
socket = connectionManager.defaultSocket;
setSocketEvents();
socket.connect();
}
private func setSocketEvents() {
// Your socket events logic
}
func attemptToIdentify(user username: String) {
socket.emit("identify", ["username": username])
}
func attemptToSend(message: String) {
socket.emit("message", ["username": username, "message": message])
}
}
So, in your AppDelegate.didFinishLaunchingWithOptions, you can now call:
Manager.shared.attemptToIdentify(user: username)
You can call this from everywhere in your code, the shared class variable will return the instance of _managerSharedInstance.
By the way, you should set your delegate of the controller in the viewWillAppear of that controller and not in the AppDelegate.
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Manager.shared.delegate = self
}
You set controller variable's object in didFinishLaunchingWithOptions method to your manager's delegate. But when you navigate ChatRoomViewController on UI, you open another ChatRoomViewController object.
You should set manager's delegate in your ChatRoomViewController class' viewDidLoad method like this
class ChatRoomViewController: UIViewController{
override func viewDidLoad(){
super.viewDidLoad()
appDelegate.manager.delegate = self
}
}

XMPP Stream Delegate Not Called? Swift 3

I am trying to connect to an XMPP server in my iOS Application. I am using the XMPPFrameworks and for some reason the XMPP Stream delegate is not being called after I try to connect to the server. I have double checked the login information using a third party XMPP application on my computer so I do not believe it is that. Am I not setting this delegate up correctly? Am I using the wrong syntax? Do I need to set this in the app delegate instead of my view controller? Any help would be much appreciated. Below is my code
import UIKit
import XMPPFramework
class ViewController: UIViewController, XMPPStreamDelegate {
override func viewDidLoad() {
super.viewDidLoad()
connect()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func connect() {
let stream = XMPPStream()
stream?.addDelegate(self, delegateQueue: DispatchQueue.main)
stream?.myJID = XMPPJID.init(string: "XXXXXXXXXXX")
stream?.hostName = "XXXXXXXXX"
stream?.hostPort = 5222
do {
try stream?.connect(withTimeout: XMPPStreamTimeoutNone)
} catch {
print("error connecting")
}
}
func xmppStreamDidConnect(sender: XMPPStream) {
print("connected!")
do {
try sender.authenticate(withPassword: "XXXXXXXXXX")
} catch {
print("error registering")
}
}
}
I think that your delegate method is not right. You can try with the delegate method given below:
#objc func xmppStreamDidConnect(_ sender: XMPPStream!) {
//write your code here.
}
try this
do {
try self.xmppController = XMPPController(hostName: server,
userJIDString: userJID,
password: userPassword)
self.xmppController.xmppStream.addDelegate(self, delegateQueue: DispatchQueue.main)
self.xmppController.connect()
} catch {
sender.showErrorMessage(message: "Something went wrong")
}
and XMPPController
class XMPPController: NSObject {
var xmppStream: XMPPStream
let hostName: String
let userJID: XMPPJID
let hostPort: UInt16
let password: String
init(hostName: String, userJIDString: String, hostPort: UInt16 = 5222, password: String) throws {
guard let userJID = XMPPJID(string: userJIDString) else {
throw XMPPControllerError.wrongUserJID
}
self.hostName = hostName
self.userJID = userJID
self.hostPort = hostPort
self.password = password
// Stream Configuration
self.xmppStream = XMPPStream()
self.xmppStream.hostName = hostName
self.xmppStream.hostPort = hostPort
self.xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicy.allowed
self.xmppStream.myJID = userJID
super.init()
self.xmppStream.addDelegate(self, delegateQueue: DispatchQueue.main)
}
func connect() {
if !self.xmppStream.isDisconnected() {
return
}
try! self.xmppStream.connect(withTimeout: XMPPStreamTimeoutNone)
}}
it works for me. required your attention this line
try self.xmppController = XMPPController(hostName: server,
userJIDString: userJID,
password: userPassword)
I had the same issue. In my case (as I followed some tutorial) the object was not global and the delegate became nil. That's why it was not called. You have to store the object which implements XMPPStreamDelegate globally.

Using NSNetService and NSNetServiceBrowser on a Swift application

I'd like to make an app that is able to discover and connect to peers on the local network, so i've decided to implement it in swift, using the bonjour framework.
However, i can't make Bonjour work using Swift, and I can't figure out why. Here is the code I use to test this service :
import Foundation
let BM_DOMAIN = "local"
let BM_TYPE = "_helloworld._tcp."
let BM_NAME = "hello"
let BM_PORT : CInt = 6543
/// Netservice
let nsns = NSNetService(domain: BM_DOMAIN,
type: BM_TYPE, name: BM_NAME, port: BM_PORT)
let nsnsdel = BMNSDelegate() //see bellow
nsns.delegate = nsnsdel
nsns.publish()
/// Net service browser.
let nsb = NSNetServiceBrowser()
let nsbdel = BMBrowserDelegate() //see bellow
nsb.delegate = nsbdel
nsb.searchForServicesOfType(BM_TYPE, inDomain: BM_DOMAIN)
println("press enter")
// this prevents the app from quitting instantly.
NSFileHandle.fileHandleWithStandardInput().availableData
The delegates are glue code that simply prints every call to the console.
class BMNSDelegate : NSObject, NSNetServiceDelegate {
func netServiceWillPublish(sender: NSNetService!) {
println("netServiceWillPublish:sender");
}
// .....and so on for the 8 other methods.....
}
class BMBrowserDelegate : NSObject, NSNetServiceBrowserDelegate {
func netServiceBrowserWillSearch(aNetServiceBrowser: NSNetServiceBrowser!){
println("netServiceBrowserWillSearch")
}
// .....and so on for the 6 other methods.....
}
Here is the output of this sample code :
netServiceWillPublish:sender
netServiceBrowserWillSearch
press enter
If I use Bonjour browser, I can see that the service is correctly published. However the callbacks in both delegates are not called, beside the **WillPublish ones :-(
After intense debugging (and reading on stackoverflow), I can't figure why it does not work. Any ideas ?
(I'm using Mac OS X 10.9.3, and xcode 6.0 beta build 6A215l)
Without your full code, it may be difficult to know, for sure, what your issue is. I suspect that you declared your variables/constants local to a function. When they went out of scope, the references to the service went out of scope. That's why you tried a blocking call requesting input from STDIN (to keep things stuck there). According to Apple documentation, netService and netServiceBrowser both implicitly associate with the default run loop, so you don't need to explicitly do that either. Explicitly associating with a run loop causes the program to get stuck, which is not what you want. This code creates the following output
netServiceWillPublish:<NSNetService 0x14522e00> local _helloworld._tcp. hello
netServiceBrowserWillSearch
netServiceDidPublish:<NSNetService 0x14522e00> local. _helloworld._tcp. hello
netServiceDidFindService
and without being blocked or in a run loop that prevents the program from proceeding normally. In AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var nsns:NSNetService?
var nsnsdel:BMNSDelegate?
var nsb:NSNetServiceBrowser?
var nsbdel:BMBrowserDelegate?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let BM_DOMAIN = "local"
let BM_TYPE = "_helloworld._tcp."
let BM_NAME = "hello"
let BM_PORT : CInt = 6543
/// Netservice
nsns = NSNetService(domain: BM_DOMAIN,
type: BM_TYPE, name: BM_NAME, port: BM_PORT)
nsnsdel = BMNSDelegate() //see bellow
nsns?.delegate = nsnsdel
nsns?.publish()
/// Net service browser.
nsb = NSNetServiceBrowser()
nsbdel = BMBrowserDelegate() //see bellow
nsb?.delegate = nsbdel
nsb?.searchForServicesOfType(BM_TYPE, inDomain: BM_DOMAIN)
//println("press enter")
// this prevents the app from quitting instantly.
// NSRunLoop.currentRunLoop().run()
// NSFileHandle.fileHandleWithStandardInput().availableData
return true
}
and the delegate callbacks elsewhere...
class BMNSDelegate : NSObject, NSNetServiceDelegate {
func netServiceWillPublish(sender: NSNetService!) {
println("netServiceWillPublish:\(sender)");
}
func netService(sender: NSNetService, didNotPublish errorDict: [NSObject : AnyObject]) {
println("didNotPublish:\(sender)");
}
func netServiceDidPublish(sender: NSNetService) {
println("netServiceDidPublish:\(sender)");
}
func netServiceWillResolve(sender: NSNetService) {
println("netServiceWillResolve:\(sender)");
}
func netService(sender: NSNetService, didNotResolve errorDict: [NSObject : AnyObject]) {
println("netServiceDidNotResolve:\(sender)");
}
func netServiceDidResolveAddress(sender: NSNetService) {
println("netServiceDidResolve:\(sender)");
}
func netService(sender: NSNetService, didUpdateTXTRecordData data: NSData) {
println("netServiceDidUpdateTXTRecordData:\(sender)");
}
func netServiceDidStop(sender: NSNetService) {
println("netServiceDidStopService:\(sender)");
}
func netService(sender: NSNetService,
didAcceptConnectionWithInputStream inputStream: NSInputStream,
outputStream stream: NSOutputStream) {
println("netServiceDidAcceptConnection:\(sender)");
}
}
class BMBrowserDelegate : NSObject, NSNetServiceBrowserDelegate {
func netServiceBrowser(netServiceBrowser: NSNetServiceBrowser,
didFindDomain domainName: String,
moreComing moreDomainsComing: Bool) {
println("netServiceDidFindDomain")
}
func netServiceBrowser(netServiceBrowser: NSNetServiceBrowser,
didRemoveDomain domainName: String,
moreComing moreDomainsComing: Bool) {
println("netServiceDidRemoveDomain")
}
func netServiceBrowser(netServiceBrowser: NSNetServiceBrowser,
didFindService netService: NSNetService,
moreComing moreServicesComing: Bool) {
println("netServiceDidFindService")
}
func netServiceBrowser(netServiceBrowser: NSNetServiceBrowser,
didRemoveService netService: NSNetService,
moreComing moreServicesComing: Bool) {
println("netServiceDidRemoveService")
}
func netServiceBrowserWillSearch(aNetServiceBrowser: NSNetServiceBrowser!){
println("netServiceBrowserWillSearch")
}
func netServiceBrowser(netServiceBrowser: NSNetServiceBrowser,
didNotSearch errorInfo: [NSObject : AnyObject]) {
println("netServiceDidNotSearch")
}
func netServiceBrowserDidStopSearch(netServiceBrowser: NSNetServiceBrowser) {
println("netServiceDidStopSearch")
}
}
NSNetServiceBrowser needs a runloop to execute. Instead of reading from stdin, call NSRunLoop.currentRunLoop().run().