This is the 14th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021.
Fans welfare: search # small program: iOS reverse, pay attention to the public number: iOS reverse welfare [digging gold booklet 50% discount code]
There is only one left, valid until 23:59 on November 30.
preface
Application scenario: Print commodity price labels and transaction receipts
Features: automatic connection to the recently used printer, unified processing bluetooth status
The problem solved: the problem of RMB ¥garbled characters
Price label printing (product name support multi-line display)
Note printing (automatic realization of % NS automatic filling space function)
“Print commodity price tag and print transaction receipts” demo source: https://download.csdn.net/download/u011018979/14920529
I, detection
1.1 Monitor bluetooth status
#define kConnecterManager [ConnecterManager sharedInstance]
#pragmaMark-******** monitors bluetooth status
//block
+ (void)listenBluetoothpoweredState:(void(^)(CBPeripheral * _Nullable peripheral))peripheral {
if (kConnecterManager.bleConnecter == nil) {
[kConnecterManager centralmanager];
[kConnecterManager didUpdateState:^(NSInteger state) {
[self setupState:state peripheral:peripheral];
}];
}
else {// The bluetooth connection status needs to be obtained
[selfsetupState:[kConnecterManager centralmanager].state peripheral:peripheral]; }}Copy the code
1.2 Unified Processing of Bluetooth status
- Unified processing of bluetooth status judgment
/** Used to handle the bluetooth state @param state <#state description#> @param Peripheral <#peripheral description#> */
+ (void)setupState:(NSInteger)state peripheral:(void(^)(CBPeripheral * _Nullable peripheral))peripheral{
switch (state) {
case CBCentralManagerStateUnsupported:
NSLog(@"The platform/hardware doesn't support Bluetooth Low Energy.");
break;
/ / CBManagerStateUnauthorized, 3 / / NSLog (@ "mobile phone bluetooth closed, please set up open the bluetooth and control center to open the bluetooth." ); break;
#pragmaMark-******** is not authorized
case CBCentralManagerStateUnauthorized:
NSLog(@"The app is not authorized to use Bluetooth Low Energy.");
//
[self setupBLEUnauthorized];
break;
//CBManagerStatePoweredOff
#pragmaMark-******** Power off
case CBCentralManagerStatePoweredOff:
NSLog(@"Bluetooth is currently powered off.");
// The system will prompt you the first time
if(QCTSession.shareQCTSession.isNOFirstShowBLEPowOff){
[self setupBLEOff];
}else{
QCTSession.shareQCTSession.isNOFirstShowBLEPowOff= YES;
}
break;
case CBCentralManagerStatePoweredOn:
[self startScane:peripheral];
NSLog(@"Bluetooth power on");
break;
case CBCentralManagerStateUnknown:
default:
break; }} + (void) setupBLEUnauthorized{
// Popup prompt
[QCTLocationServiceUtil setupCentralManagerState_not_authorized];
// Update bluetooth status to Disconnected when bluetooth is turned off
[QCTSession clearPrintInfo];
// Notifies the controller of updates to pair device list information
[[NSNotificationCenter defaultCenter] postNotificationName:QCTQCTBluetoothListViewControllerreloadDateNotification object: nil];
}
+ (void) setupBLEOff{
// Popup prompt
[QCTLocationServiceUtil setupCentralManagerStatePoweredOff];
// Update bluetooth status to Disconnected when bluetooth is turned off
[QCTSession clearPrintInfo];
// Notifies the controller of updates to pair device list information
[[NSNotificationCenter defaultCenter] postNotificationName:QCTQCTBluetoothListViewControllerreloadDateNotification object: nil];
}
Copy the code
II, processing,
2.0 Handle unauthorized situations
- setupCentralManagerState_not_authorized
+ (void) setupCentralManagerState_not_authorized{
NSString *tips = "Mobile phone bluetooth function does not have permission, please go to Settings.";
[LBAlertController showAlertTitle:@" Unable to use Bluetooth" content:tips cancelString:@ "sure" cancleBlock :^{
/ / 322
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString[[]]) {UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
} sureString:nil sureBlock:nil currentController:[QCT_Common getCurrentVC]];
}
Copy the code
2.1 Handling the Closed state
- setupCentralManagerStatePoweredOff
NSString *tips = "Mobile phone Bluetooth function is off, please go to the Settings to enable Bluetooth and control center to enable Bluetooth.";
[LBAlertController showAlertTitle:@" Unable to use Bluetooth" content:tips cancelString:@ "sure" cancleBlock :^{
/ / 322
if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]) {// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
} sureString:nil sureBlock:nil currentController:[QCT_Common getCurrentVC]];
Copy the code
III Basic Knowledge
3.1 Three Modes of Forward Setting
Method 1: prefs:root= A service is applicable to oss smaller than iOS10. Mode 2: prefs:root=bundleID This mode is applicable to oss greater than or equal to iOS8 and smaller than iOS10. Mode 3: prefs:root=bundleIDUIApplicationOpenSettingsURLStringVersion >= iOS10: you can switch to your own application Settings, but not to system SettingsCopy the code
- Pay attention to
NSURL *url = [NSURL URLWithString:@"App-Prefs:root=Bluetooth"]; The above formula will be rejected when uploading APPStore. You can change it to the following formula:// Convert the string to hexadecimal, convert it, and then call it, depending on the face
NSData *encryptString = [[NSData alloc] initWithBytes:(unsigned char[]) {0x41.0x70.0x70.0x2d.0x50.0x72.0x65.0x66.0x73.0x3a.0x72.0x6f.0x6f.0x74.0x3d.0x42.0x6c.0x75.0x65.0x74.0x6f.0x6f.0x74.0x68} length:24];
NSString *string = [[NSString alloc] initWithData:encryptString encoding:NSUTF8StringEncoding];
Copy the code
3.2 Complete code for ConnecterManager
- m
//
#import "ConnecterManager.h"
@interface ConnecterManager(a){
/** This was created just to get the status of the listener */
ConnectMethod currentConnMethod;
}
@end
@implementation ConnecterManager
/ * * 1, bluetooth application only supports the front desk Use these tips to use, you need to call connectPeripheral: options: method is introduced to the following parameters. CBConnectPeripheralOptionNotifyOnConnectionKey: after the application hangs, establish connection with the specified peripheral success, has issued a circular, for printing operations? CBConnectPeripheralOptionNotifyOnDisconnectionKey: after the application hangs, if the specified peripheral disconnected, has issued a circular, to reconnect? CBConnectPeripheralOptionNotifyOnNotificationKey: After the application is suspended, any notification on the specified peripheral will be prompted. Background execution Mode There are two Bluetooth background modes, one for Central role and the other for Peripheral role. If your application requires two roles, you can declare support for both modes. Declaration: Increment UIBackgroundModes keys and increment array values containing the following strings. • Bluetooth - Central -- The app communicates with Bluetooth Low Energy peripherals using The Core Bluetooth Framework Bluetooth-peripheral -- The app Shares data using The Core Bluetooth Framework then The application will be able to process specific Bluetooth-related events in The background. Even in the background, you can still discover and connect to peripherals, and you can retrieve and read and write data. When the CBCentralManagerDelegate or CBPeripheralDelegate delegate delegate event occurs, the system will wake up the application to process it. 1, CBCentralManagerScanOptionAllowDuplicatesKey this key is ignored, many times found found the same peripheral will be merged into one event. 2. If all the apps in the scan are in the background, your app's scan gap will be longer. As a result, it may take longer to scan the peripheral. The idea is to reduce radiation and save power. If you want to support The Peripheral Background Execution Mode of a peripheral role, The peripheral Background Execution Mode will be enabled. You need to add UIBackgroundModes keys to the info.plist and include bluetooth-Peripheral values in the values. This wakes up the application to handle read/write and subscribe events. The Core Bluetooth Framework not only allows your application to wake up to handle read/write and subscribe requests, but also allows your application to broadcast in background state. But you have to be aware that background broadcasting is different from foreground broadcasting. Even so, you must pay attention to the difference between background and foreground broadcast processing. Especially if your application needs to send a broadcast in the background. 1, CBAdvertisementDataLocalNameKey this key will be ignored, and peripheral local name will not be broadcast 2, CBAdvertisementDataServiceUUIDsKey values contained in all the service uuids will be put into the "overflow" area; These values are only found when the ios device display indicates that it is searched. 3. If all applications in the broadcast state are in the background, the broadcast frequency will be reduced. @return <#return value description#> */
- (CBCentralManager *)centralmanager{
if (nil == _centralmanager) {
/ / / / CBCentralManagerOptionShowPowerAlertKey: initialization if bluetooth didn't open the prompt dialog box will appear
/ / CBCentralManagerOptionRestoreIdentifierKey: killed used in process of bluetooth connection is restored
// dispatch_queue_t centeralQueue = dispatch_queue_create("CenterQueue", DISPATCH_QUEUE_SERIAL);
_centralmanager =[[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_global_queue(0.0) options:@{CBCentralManagerOptionShowPowerAlertKey : [NSNumber numberWithBool:YES]}];
/ / if choose to support state saving, and reduction of only one CBCentralMnager object instance is applied to implement the central role, so in the initialization time initialization options increase CBCentralManagerOptionRestoreIdentifierKey key, And assign the restore ID.
//
/ / in the realization of application: didFinishLaunchingWithOptions: When I do this proxy method, By using the parameters of the launchoptions key (UIApplicationLaunchOptionsBluetoothCentralsKey or UIApplicationLaunchOptionsBluetoothPeripheralsKey) can be obtained at the termination of the application in save VAT id list for us.
//
//
/ /...
// Once you have the restore ID list, you can restore the Central Manager object. Note: When the application is activated, the system only provides restore ids for those Central and Peripheral Managers whose Bluetooth tasks occur when the application terminates.
// Implement the restore proxy method
//
// After recreating Central and Peripheral Managers, you need to restore their state via bluetooth. For central managers, in order to realize centralManager: willRestoreState: proxy approach, for the peripheral managers realize peripheralManager: willRestoreState: Methods.
//
}
return _centralmanager;
}
/** typedef NS_ENUM(NSInteger, CBManagerState) {CBManagerStateUnknown = 0, Please check the phone CBManagerStateResetting, 1 / / phone bluetooth disconnected, reset. CBManagerStateUnsupported, 2 / / mobile phone does not support bluetooth function, please replace the phone CBManagerStateUnauthorized, 3 / / NSLog (@ "mobile phone bluetooth closed, please set up open the bluetooth and control center to open the bluetooth." ); break; CBManagerStatePoweredOff, 4 / / NSLog (@ "." ); break; CBManagerStatePoweredOn, 5 / / NSLog (@ "bluetooth open and available"); break; } NS_ENUM_AVAILABLE(10_13, 10_0); @param central <#central description#> */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
NSLog(@"centralManagerDidUpdateState: %ld",central.state);//5 UIGestureRecognizerStateFailed
}
static ConnecterManager *manager;
static dispatch_once_tonce; + (instancetype)sharedInstance {
dispatch_once(&once, ^{
manager = [[ConnecterManager alloc]init];
});
return manager;
}
/** * Connect to a network device with a specified IP address and port number. * @param IP IP address of the device. * @param port Port number of the device- (void)connectIP:(NSString *)ip port:(int)port connectState:(void (^)(ConnectState state))connectState callback:(void(^) (NSData *))callback {
dispatch_async(dispatch_get_global_queue(0.0), ^ {if (_ethernetConnecter == nil) {
currentConnMethod = ETHERNET;
[self initConnecter:currentConnMethod];
}
[_ethernetConnecter connectIP:ip port:port connectState:connectState callback:callback];
});
}
* @param serviceUUIDs needs to find the UUID of the peripheral. Set it to nil to find all peripherals. * @param options Options * @param Discover Discovered devices */- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options discover:(void(^_Nullable)(CBPeripheral *_Nullable peripheral,NSDictionary<NSString *, id> *_Nullable advertisementData,NSNumber *_Nullable RSSI))discover{
[_bleConnecter scanForPeripheralsWithServices:serviceUUIDs options:options discover:discover];
}
/** * Update bluetooth status * @param state Bluetooth status */- (void)didUpdateState:(void(^) (NSInteger state))state {
if (_bleConnecter == nil) {
currentConnMethod = BLUETOOTH;
[selfinitConnecter:currentConnMethod]; } [_bleConnecter didUpdateState:state]; } - (void)initConnecter:(ConnectMethod)connectMethod {
switch (connectMethod) {
case BLUETOOTH:
_bleConnecter = [BLEConnecter new];
_connecter = _bleConnecter;
break;
case ETHERNET:
_ethernetConnecter = [EthernetConnecter new];
_connecter = _ethernetConnecter;
break;
default:
break; }}/** * Method description: Stop scanning */- (void)stopScan {
[_bleConnecter stopScan];
}
/** * connect */- (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary<NSString *,id> *)options timeout:(NSUInteger)timeout connectBlack:(void(^_Nullable)(ConnectState state)) connectState{
dispatch_async(dispatch_get_main_queue(), ^{
[self->_bleConnecter connectPeripheral:peripheral options:options timeout:timeout connectBlack:connectState]; }); } - (void)connectPeripheral:(CBPeripheral * _Nullable)peripheral options:(nullable NSDictionary<NSString *,id> *)options { [_bleConnecter connectPeripheral:peripheral options:options]; } - (void)write:(NSData *_Nullable)data progress:(void(^_Nullable)(NSUInteger total,NSUInteger progress))progress receCallBack:(void (^_Nullable)(NSData*_Nullable))callBack { [_bleConnecter write:data progress:progress receCallBack:callBack]; } - (void)write:(NSData *)data receCallBack:(void(^) (NSData *))callBack {
#ifdef DEBUG
NSLog(@"[ConnecterManager] write:receCallBack:");
#endif
_bleConnecter.writeProgress = nil; [_connecter write:data receCallBack:callBack]; } - (void)write:(NSData *)data {
#ifdef DEBUG
NSLog(@"[ConnecterManager] write:");
#endif
_bleConnecter.writeProgress = nil;
[_connecter write:data];
}
/** // stop scanning and disconnect -(void)disconnectPeripheral:(CBCentralManager *)centralManager Peripheral :(CBPeripheral *)peripheral{// stop peripheral scan [centralManager stopScan]; / / disconnected [centralManager cancelPeripheralConnection: peripheral]; }
*/- (void)close {
if (_connecter) {
[_connecter close];
}
switch (currentConnMethod) {
case BLUETOOTH:
_bleConnecter = nil;
break;
case ETHERNET:
_ethernetConnecter = nil;
break; }}@end
Copy the code
- h
//
#import <Foundation/Foundation.h>
#import "BLEConnecter.h"
#import "EthernetConnecter.h"
#import "Connecter.h"
/** * @enum ConnectMethod * @discussion Connection mode * @constant BLUETOOTH connection * @Constant ETHERNET network port connection (wifi connection) */
typedef enum : NSUInteger{
BLUETOOTH,
ETHERNET
}ConnectMethod;
#define kConnecterManager [ConnecterManager sharedInstance]
@interface ConnecterManager : NSObject
/** Currently used to determine bluetooth status */
@property(nonatomic.strong) CBCentralManager *centralmanager;
@property(nonatomic.strong)BLEConnecter *bleConnecter;
@property(nonatomic.strong)EthernetConnecter *ethernetConnecter;
@property(nonatomic.strong)Connecter *connecter; + (instancetype)sharedInstance;
/** * Connect to a network device with a specified IP address and port number. * @param IP IP address of the device. * @param port Port number of the device- (void)connectIP:(NSString *)ip port:(int)port connectState:(void (^)(ConnectState state))connectState callback:(void(^) (NSData *))callback;
/** * Close the connection */- (void)close;
/** * Method description: write data to the output stream (bluetooth only) * @param data Data to be written * @param progress Progress of writing data * @param callBack reads data from the input stream */- (void)write:(NSData *_Nullable)data progress:(void(^_Nullable)(NSUInteger total,NSUInteger progress))progress receCallBack:(void (^_Nullable)(NSData *_Nullable))callBack;
/** * write data to the output stream * @param callBack read data interface */- (void)write:(NSData *)data receCallBack:(void(^) (NSData *))callBack;
/** * Write data to the output stream * @param data To write data */- (void)write:(NSData *)data;
/** * Method description: Stop scanning */- (void)stopScan;
/** * Update bluetooth status * @param state Bluetooth status */- (void)didUpdateState:(void(^) (NSInteger state))state;
/** * Method description: Connect peripheral * @param Peripheral to connect * @param options Other optional operations * @param timeout Connection time * @param connectState connection state */- (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary<NSString *,id> *)options timeout:(NSUInteger)timeout connectBlack:(void(^_Nullable)(ConnectState state)) connectState;
/** * Connect peripherals * @param options Other optional operations */- (void)connectPeripheral:(CBPeripheral * _Nullable)peripheral options:(nullable NSDictionary<NSString *,id> *)options;
* @param serviceUUIDs needs to find the UUID of the peripheral. Set it to nil to find all peripherals. * @param options Options * @param Discover Discovered devices */- (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options discover:(void(^_Nullable)(CBPeripheral *_Nullable peripheral,NSDictionary<NSString *, id> *_Nullable advertisementData,NSNumber *_Nullable RSSI))discover;
@end
Copy the code
IV 、see also
More content please pay attention to # applets: iOS Reverse, only to present valuable information for you, focus on mobile technology research field; For more services and consultation, please pay attention to the public number: iOS Reverse.