Est-il possible d'exécuter un périphérique iOS 7 en tant que périphérique Bluetooth LE (iBeacon) et de le faire de la publicité en arrière-plan? J'ai pu le faire apparaître au premier plan avec le code ci-dessous et je peux le voir depuis un autre appareil iOS, mais dès que je reviens à l'écran d'accueil, la publicité s'arrête. J'ai ajouté le mode arrière-plan Bluetooth-Périphérique dans le plist, mais cela n'a pas semblé aider, bien que je reçoive l'invite indiquant que l'appareil souhaite utiliser le Bluetooth en arrière-plan. Est-ce que je fais quelque chose de mal ou est-ce simplement impossible dans iOS 7?
peripManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
return;
}
NSString *identifier = @"MyBeacon";
//Construct the region
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:identifier];
//Passing nil will use the device default power
NSDictionary *payload = [beaconRegion peripheralDataWithMeasuredPower:nil];
//Start advertising
[peripManager startAdvertising:payload];
}
Voici le code qui se trouve du côté réception/écoute:
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region
{
//Check if we have moved closer or farther away from the iBeacon…
if (beacons.count > 0) {
CLBeacon *beacon = [beacons objectAtIndex:0];
switch (beacon.proximity) {
case CLProximityImmediate:
[self log:[NSString stringWithFormat:@"You're Sitting on it! %li", (long)beacon.rssi]];
break;
case CLProximityNear:
[self log:[NSString stringWithFormat:@"Getting Warmer! %li", (long)beacon.rssi]];
break;
default:
[self log:[NSString stringWithFormat:@"It's around here somewhere! %li", (long)beacon.rssi]];
break;
}
}
}
Les publicités CoreBluetooth standard peuvent être diffusées lorsque l'application est en arrière-plan, mais pas si elles ont été lancées avec le dictionnaire CLBeaconRegion
. La solution consiste à abandonner complètement le framework CoreLocation et à créer votre propre "framework" de proximité en utilisant uniquement CoreBlueTooth.
Vous devez toujours utiliser les spécificateurs d'arrière-plan appropriés dans le fichier Info.plist (par exemple, bluetooth-peripheral
et bluetooth-central
).
Le code ressemble à ceci:
1) créer une publication périphérique standard à l'aide de CBPeripheralManager
NSDictionary *advertisingData = @{CBAdvertisementDataLocalNameKey:@"my-peripheral",
CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:identifier]]};
// Start advertising over BLE
[peripheralManager startAdvertising:advertisingData];
2) utilisez use CBCentralManager
pour rechercher ce service à l'aide de l'UUID que vous avez spécifié.
NSDictionary *scanOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)};
NSArray *services = @[[CBUUID UUIDWithString:identifier]];
[centralManager scanForPeripheralsWithServices:services options:scanOptions];
3) dans la méthode CBCentralManagerDelegate
didDiscoverPeripheral
, lisez la valeur RSSI
de l'annonce.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"RSSI: %d", [RSSI intValue]);
}
4) Traduisez les valeurs RSSI dans une distance.
- (INDetectorRange)convertRSSItoINProximity:(NSInteger)proximity
{
if (proximity < -70)
return INDetectorRangeFar;
if (proximity < -55)
return INDetectorRangeNear;
if (proximity < 0)
return INDetectorRangeImmediate;
return INDetectorRangeUnknown;
}
J'ai constaté que je devais «assouplir» ou «faire la moyenne» des valeurs RSSI pour obtenir quelque chose de réalisable. Cela n’est pas différent de lorsque vous travaillez avec des données de capteur (par exemple, des données d’accéléromètre).
J'espère que ce concept fonctionnera pleinement pour le publier quelque part à un moment donné.
Utilisez également le docs _ (Guide de programmation Bluetooth de base) si vous êtes bloqué.
Update: A l'exemple de code complet est actif sur Github . J'ai travaillé dessus dans le cadre d'un projet lié au travail .
Mise à jour n ° 2: _ Apple publie des améliorations majeures du comportement en arrière-plan d'iBeacon pour iOS7.1
Le Pouvez-vous sentir l'iBeacon? article traite à la fois de l'utilisation de Estimotes et de la publicité provenant de Mac et d'appareils iOS. Vous devez vérifier la capacité «Agit comme accessoire Bluetooth LE» dans la cible du projet.
Non, les appareils iOS annoncent iBeacon uniquement lorsque l'application qui en fait la publicité est au premier plan. Ainsi, si vous passez à une autre application ou si l'appareil se met en veille, la publication s'arrête.
Bien sûr, si vous voulez vraiment que la publication continue, désactivez le minuteur en veille et effectuez un accès guidé afin que le périphérique iOs ne se mette pas en veille et que personne ne puisse passer à une autre application.
J'espère également pouvoir configurer mon application (test) pour annoncer un iBeacon en arrière-plan. Les documents de la clé info.plist de UIBackgroundModes suggèrent que la clé de périphérique Bluetooth pourrait fonctionner, mais il semble que cela ne fonctionne pas. (Je viens de le tester il y a quelques minutes.)
Ce que je fais pour l'instant est de désactiver le minuteur d'inactivité, comme le suggère RawMean, puis de régler la luminosité de l'écran sur 0. Enfin, lorsque mon application de test se comporte comme un iBeacon, j'ajoute un gestionnaire d'événements shake qui allume l'écran à nouveau pendant 30 secondes. Baisser l’écran aussi bas que possible permet de réduire quelque peu l’épuisement de la batterie.
Ceci peut être fait. Je ne veux pas que les ingénieurs Apple soient en colère à ma porte, je ne publierai donc pas l'algorithme.
En résumé, la zone overflow qui code les UUID du service est simplement un groupe d'octets transmis par liaison radio. Vous pouvez le sentir vous-même. En particulier, il s'agit d'un hachage court qui est ensuite représenté par un codage à chaud. Plusieurs UUID sont communiqués en configurant plusieurs bits. Vous aurez des collisions de cette façon. Par exemple, l'UUID 1001 aura le même encodage que 3333. Vous pouvez le vérifier vous-même: ayez un UUID 1001 diffusé sur un iPhone en arrière-plan et demandez à l'autre de rechercher 3333. Il pensera effectivement recevoir 3333.