文章的目的为了记录使用Objective-C 进行IOS app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 Objective-C IOS 应用开发(一)macOS 的使用
开源 Objective-C IOS 应用开发(二)Xcode安装
开源 Objective-C IOS 应用开发(三)第一个iPhone的APP
开源 Objective-C IOS 应用开发(四)Xcode工程文件结构
开源 Objective-C IOS 应用开发(五)iOS操作(action)和输出口(Outlet)
开源 Objective-C IOS 应用开发(六)Objective-C 和 C语言
开源 Objective-C IOS 应用开发(七)Objective-C核心代码示例
开源 Objective-C IOS 应用开发(八)常见控件UI
开源 Objective-C IOS 应用开发(九)复杂控件-tableview
开源 Objective-C IOS 应用开发(十)数据持久化--文件
开源 Objective-C IOS 应用开发(十一)数据持久化--sqlite
开源 Objective-C IOS 应用开发(十二)通讯--ble
开源 Objective-C IOS 应用开发(十三)通讯--Http访问
开源 Objective-C IOS 应用开发(十四)传感器--陀螺仪和gps
开源 Objective-C IOS 应用开发(十五)通讯--蓝牙ble扫描
开源 Objective-C IOS 应用开发(十六)Storyboard模式下的纯代码界面
开源 Objective-C IOS 应用开发(十七)CAF音频的录制
开源 Objective-C IOS 应用开发(十八)音频的播放
开源 Objective-C IOS 应用开发(十九)视频的播放
开源 Objective-C IOS 应用开发(二十)多线程处理
开源 Objective-C IOS 应用开发(二十一)自定义控件--示波器
开源 Objective-C IOS 应用开发(二十二)自定义控件--车速仪表盘
推荐链接:
开源 Arkts 鸿蒙应用 开发(一)工程文件分析-优快云博客
开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-优快云博客
开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-优快云博客
开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-优快云博客
开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-优快云博客
开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储-优快云博客
开源 Arkts 鸿蒙应用 开发(七)数据持久--sqlite关系数据库-优快云博客
开源 Arkts 鸿蒙应用 开发(八)多媒体--相册和相机-优快云博客
开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端-优快云博客
开源 Arkts 鸿蒙应用 开发(十)通讯--Http-优快云博客
开源 Arkts 鸿蒙应用 开发(十一)证书和包名修改-优快云博客
开源 Arkts 鸿蒙应用 开发(十二)传感器的使用-优快云博客
开源 Arkts 鸿蒙应用 开发(十三)音频--MP3播放_arkts avplayer播放音频 mp3-优快云博客
开源 Arkts 鸿蒙应用 开发(十四)线程--任务池(taskpool)-优快云博客
开源 Arkts 鸿蒙应用 开发(十五)自定义绘图控件--仪表盘-优快云博客
开源 Arkts 鸿蒙应用 开发(十六)自定义绘图控件--波形图-优快云博客
开源 Arkts 鸿蒙应用 开发(十七)通讯--http多文件下载-优快云博客
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器-优快云博客
推荐链接:
开源 java android app 开发(一)开发环境的搭建-优快云博客
开源 java android app 开发(二)工程文件结构-优快云博客
开源 java android app 开发(三)GUI界面布局和常用组件-优快云博客
开源 java android app 开发(四)GUI界面重要组件-优快云博客
开源 java android app 开发(五)文件和数据库存储-优快云博客
开源 java android app 开发(六)多媒体使用-优快云博客
开源 java android app 开发(七)通讯之Tcp和Http-优快云博客
开源 java android app 开发(八)通讯之Mqtt和Ble-优快云博客
开源 java android app 开发(九)后台之线程和服务-优快云博客
开源 java android app 开发(十)广播机制-优快云博客
开源 java android app 开发(十一)调试、发布-优快云博客
开源 java android app 开发(十二)封库.aar-优快云博客
本章内容主要是BLE 广播应用,文本框可以输入设备名称,点击发送进行广播。
目录:
1.手机演示
2.所有源码
3.源码分析
一、手机演示
左边为ipone app,右边为安卓的ble调试助手

二、所有源码
AppDelegate.h
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
ViewController *viewController = [[ViewController alloc] init];
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface ViewController : UIViewController <CBPeripheralManagerDelegate, UITextFieldDelegate>
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) UITextField *nameTextField;
@property (nonatomic, strong) UIButton *startButton;
@property (nonatomic, strong) UIButton *stopButton;
@property (nonatomic, strong) UILabel *statusLabel;
@end
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, assign) BOOL isAdvertising;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
[self setupBLE];
}
- (void)setupUI {
self.view.backgroundColor = [UIColor whiteColor];
// 标题
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.text = @"BLE广播发送器";
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = [UIColor blackColor];
titleLabel.font = [UIFont boldSystemFontOfSize:24];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:titleLabel];
// 设备名称标签
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.text = @"设备名称:";
nameLabel.textColor = [UIColor blackColor];
nameLabel.font = [UIFont systemFontOfSize:16];
nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:nameLabel];
// 设备名称输入框
self.nameTextField = [[UITextField alloc] init];
self.nameTextField.placeholder = @"输入BLE设备名称";
self.nameTextField.borderStyle = UITextBorderStyleRoundedRect;
self.nameTextField.text = @"MyBLEDevice";
self.nameTextField.delegate = self;
self.nameTextField.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.nameTextField];
// 状态标签
self.statusLabel = [[UILabel alloc] init];
self.statusLabel.text = @"准备就绪";
self.statusLabel.textAlignment = NSTextAlignmentCenter;
self.statusLabel.textColor = [UIColor grayColor];
self.statusLabel.font = [UIFont systemFontOfSize:16];
self.statusLabel.numberOfLines = 0;
self.statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.statusLabel];
// 开始广播按钮
self.startButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.startButton setTitle:@"开始广播" forState:UIControlStateNormal];
[self.startButton addTarget:self action:@selector(startAdvertising) forControlEvents:UIControlEventTouchUpInside];
self.startButton.backgroundColor = [UIColor systemGreenColor];
self.startButton.tintColor = [UIColor whiteColor];
self.startButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.startButton.layer.cornerRadius = 10;
self.startButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.startButton];
// 停止广播按钮
self.stopButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.stopButton setTitle:@"停止广播" forState:UIControlStateNormal];
[self.stopButton addTarget:self action:@selector(stopAdvertising) forControlEvents:UIControlEventTouchUpInside];
self.stopButton.backgroundColor = [UIColor systemRedColor];
self.stopButton.tintColor = [UIColor whiteColor];
self.stopButton.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.stopButton.layer.cornerRadius = 10;
self.stopButton.translatesAutoresizingMaskIntoConstraints = NO;
self.stopButton.enabled = NO;
self.stopButton.backgroundColor = [UIColor systemGrayColor];
[self.view addSubview:self.stopButton];
// 说明标签
UILabel *infoLabel = [[UILabel alloc] init];
infoLabel.text = @"模式: 不可连接广播 - 无任何服务";
infoLabel.textAlignment = NSTextAlignmentCenter;
infoLabel.textColor = [UIColor lightGrayColor];
infoLabel.font = [UIFont systemFontOfSize:14];
infoLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:infoLabel];
// 设置约束
[self setupConstraintsWithTitleLabel:titleLabel nameLabel:nameLabel infoLabel:infoLabel];
// 添加点击手势隐藏键盘
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tapGesture];
}
- (void)setupConstraintsWithTitleLabel:(UILabel *)titleLabel nameLabel:(UILabel *)nameLabel infoLabel:(UILabel *)infoLabel {
[NSLayoutConstraint activateConstraints:@[
// 标题约束
[titleLabel.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:20],
[titleLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[titleLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[titleLabel.heightAnchor constraintEqualToConstant:40],
// 名称标签约束
[nameLabel.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:40],
[nameLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[nameLabel.widthAnchor constraintEqualToConstant:80],
[nameLabel.heightAnchor constraintEqualToConstant:40],
// 名称输入框约束
[self.nameTextField.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:40],
[self.nameTextField.leadingAnchor constraintEqualToAnchor:nameLabel.trailingAnchor constant:10],
[self.nameTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[self.nameTextField.heightAnchor constraintEqualToConstant:40],
// 状态标签约束
[self.statusLabel.topAnchor constraintEqualToAnchor:self.nameTextField.bottomAnchor constant:30],
[self.statusLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[self.statusLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[self.statusLabel.heightAnchor constraintEqualToConstant:60],
// 开始按钮约束
[self.startButton.topAnchor constraintEqualToAnchor:self.statusLabel.bottomAnchor constant:40],
[self.startButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:50],
[self.startButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-50],
[self.startButton.heightAnchor constraintEqualToConstant:50],
// 停止按钮约束
[self.stopButton.topAnchor constraintEqualToAnchor:self.startButton.bottomAnchor constant:20],
[self.stopButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:50],
[self.stopButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-50],
[self.stopButton.heightAnchor constraintEqualToConstant:50],
// 说明标签约束
[infoLabel.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:-20],
[infoLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[infoLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[infoLabel.heightAnchor constraintEqualToConstant:30]
]];
}
- (void)setupBLE {
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
self.isAdvertising = NO;
}
- (void)dismissKeyboard {
[self.nameTextField resignFirstResponder];
}
#pragma mark - Button Actions
- (void)startAdvertising {
[self dismissKeyboard];
if (self.peripheralManager.state != CBManagerStatePoweredOn) {
self.statusLabel.text = @"错误: 蓝牙未开启";
return;
}
if (self.isAdvertising) {
self.statusLabel.text = @"错误: 已在广播中";
return;
}
NSString *deviceName = [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (deviceName.length == 0) {
self.statusLabel.text = @"错误: 请输入设备名称";
return;
}
[self startNonConnectableAdvertisingWithName:deviceName];
}
- (void)stopAdvertising {
if (self.isAdvertising) {
[self.peripheralManager stopAdvertising];
self.isAdvertising = NO;
self.statusLabel.text = @"广播已停止";
self.startButton.enabled = YES;
self.stopButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGreenColor];
self.stopButton.backgroundColor = [UIColor systemGrayColor];
NSLog(@"BLE广播已停止");
}
}
#pragma mark - 不可连接广播实现
- (void)startNonConnectableAdvertisingWithName:(NSString *)deviceName {
// 使用空的Service UUIDs数组来实现不可连接广播
// 空的UUID数组表示设备没有可用的服务,因此不可连接
NSDictionary *advertisementData = @{
CBAdvertisementDataLocalNameKey : deviceName,
CBAdvertisementDataServiceUUIDsKey : @[] // 空数组 - 关键!
};
[self.peripheralManager startAdvertising:advertisementData];
self.statusLabel.text = [NSString stringWithFormat:@"正在广播: %@\n设备不可连接", deviceName];
NSLog(@"开始不可连接广播,设备名称: %@", deviceName);
}
#pragma mark - CBPeripheralManagerDelegate
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
NSString *stateString;
UIColor *statusColor = [UIColor grayColor];
switch (peripheral.state) {
case CBManagerStatePoweredOn:
stateString = @"蓝牙已就绪\n请输入设备名称并开始广播";
statusColor = [UIColor systemBlueColor];
self.startButton.enabled = YES;
self.startButton.backgroundColor = [UIColor systemGreenColor];
break;
case CBManagerStatePoweredOff:
stateString = @"蓝牙未开启\n请打开系统蓝牙设置";
statusColor = [UIColor systemRedColor];
self.startButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGrayColor];
break;
case CBManagerStateUnauthorized:
stateString = @"未授权蓝牙权限\n请在设置中允许蓝牙访问";
statusColor = [UIColor systemOrangeColor];
self.startButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGrayColor];
break;
case CBManagerStateUnsupported:
stateString = @"设备不支持BLE";
statusColor = [UIColor systemRedColor];
self.startButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGrayColor];
break;
default:
stateString = @"蓝牙状态未知";
self.startButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGrayColor];
break;
}
self.statusLabel.text = stateString;
self.statusLabel.textColor = statusColor;
NSLog(@"蓝牙状态: %@", stateString);
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error {
if (error) {
self.statusLabel.text = [NSString stringWithFormat:@"广播启动失败\n%@", error.localizedDescription];
self.statusLabel.textColor = [UIColor systemRedColor];
NSLog(@"广播错误: %@", error.localizedDescription);
self.isAdvertising = NO;
self.startButton.enabled = YES;
self.stopButton.enabled = NO;
self.startButton.backgroundColor = [UIColor systemGreenColor];
self.stopButton.backgroundColor = [UIColor systemGrayColor];
} else {
NSString *deviceName = [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.statusLabel.text = [NSString stringWithFormat:@"广播成功: %@\n设备不可连接", deviceName];
self.statusLabel.textColor = [UIColor systemGreenColor];
self.isAdvertising = YES;
self.startButton.enabled = NO;
self.stopButton.enabled = YES;
self.startButton.backgroundColor = [UIColor systemGrayColor];
self.stopButton.backgroundColor = [UIColor systemRedColor];
NSLog(@"不可连接广播已成功启动: %@", deviceName);
}
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// 编辑时停止广播
if (self.isAdvertising) {
[self stopAdvertising];
}
}
@end
main.m
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
info.plist
<key>NSBluetoothAlwaysUsageDescription</key>
<string>此应用需要蓝牙权限来发送BLE广播</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>此应用需要蓝牙权限来发送BLE广播</string>

三、源码分析
1. 项目架构概述
这是一个基于 CoreBluetooth 框架的 iOS 应用,主要功能是作为 BLE 外设发送不可连接的广播信号。
2. 核心组件分析
2.1 AppDelegate - 应用入口
objective-c
// 创建主窗口和根视图控制器
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
ViewController *viewController = [[ViewController alloc] init];
self.window.rootViewController = viewController;
-
设置应用的主窗口
-
初始化并设置 ViewController 为根视图控制器
-
显示窗口
2.2 ViewController - 主控制器
2.2.1 UI 界面构建
界面元素:
-
titleLabel: 应用标题 -
nameTextField: 设备名称输入框 -
statusLabel: 状态显示标签 -
startButton/stopButton: 开始/停止广播按钮 -
infoLabel: 模式说明标签
布局特点:
-
使用 Auto Layout 约束进行响应式布局
-
支持安全区域适配
-
美观的按钮样式和颜色配置
2.2.2 BLE 核心功能
初始化蓝牙:
objective-c
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
-
在主队列初始化外设管理器
-
设置委托为 self
不可连接广播实现:
objective-c
NSDictionary *advertisementData = @{
CBAdvertisementDataLocalNameKey : deviceName,
CBAdvertisementDataServiceUUIDsKey : @[] // 空数组 - 关键!
};
关键点: 使用空的 Service UUIDs 数组使设备不可连接
2.2.3 状态管理
蓝牙状态处理:
objective-c
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
处理所有可能的蓝牙状态:
-
CBManagerStatePoweredOn: 蓝牙就绪 -
CBManagerStatePoweredOff: 蓝牙关闭 -
CBManagerStateUnauthorized: 未授权 -
CBManagerStateUnsupported: 不支持 BLE
广播状态反馈:
objective-c
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
处理广播启动成功或失败的情况
3. 功能流程分析
3.1 启动流程
-
应用启动 → AppDelegate 初始化窗口
-
ViewController 加载 → 初始化 UI 和 BLE
-
检查蓝牙状态 → 更新界面状态
3.2 广播流程
-
用户输入设备名称
-
点击"开始广播"按钮
-
验证蓝牙状态和设备名称
-
启动不可连接广播
-
更新界面状态和按钮状态
3.3 停止流程
-
点击"停止广播"按钮
-
调用
stopAdvertising方法 -
重置界面状态
Objective-C实现iOS蓝牙BLE广播
526

被折叠的 条评论
为什么被折叠?



