Delphi IOS 蓝牙锁屏后台运行
Delphi IOS 后台运行
同样的程序,编译成android,锁屏后继续运行正常,蓝牙通讯正常,但在IOS下锁屏后程序的蓝牙就中断通讯了?
IOS的机制就是这样,锁屏就关闭了。
音乐播放器是怎么做到的?锁屏还能继续工作?
查看iPhone手机,关闭后台刷新,依然可以播放音乐。
另外还有系统设置里的后台刷新打开还是关闭状态。
写个单独的循环累加,显示结果值的程序,加上audio、bluetooth-central、bluetooth-peripheral三个选项,锁屏依然停止状态。看来还是要写线程代码。
delphi的例子MusicPlayer,加上audio选项,锁屏播放正常。不加audio选项,锁屏即停止!如果不加audio,加上bluetooth-central锁屏后报错了。让music支持后台运行正常,主界面上加载一个循环累计变量,锁屏后也是停止运行了,
但是进度条tbProgress是解锁后恢复正常,显示准确的进度,但是我的iii循环累计变量停止接着上次值开始累计了。
只能是后台(线程)运行了。
线程也不行,调试跟踪music,锁屏后,线程所有函数都不执行了。停止了。回复后才读取最新的进度,信息。但是
UIBackgroundModes
Delphi>Project Options>Version>UIBackgroundModes
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Version_Info
http://community.embarcadero.com/blogs/blog-menu/entry/background-modes-in-ios
蓝牙Background
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Using_Bluetooth_Low_Energy
audio
location
voip
newsstand-content
external-accessory
bluetooth-central
bluetooth-peripheral
fetch
remote-notification
Information Property List Key Reference
https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/plist/info/UIBackgroundModes
Background Execution
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
music background run
http://community.embarcadero.com/blogs/blog-menu/blogger/listings/miguel-oliver-embarcadero-com
Communicating with a Bluetooth Accessory
Apps that work with Bluetooth peripherals can ask to be woken up if the peripheral delivers an update when the app is suspended. This support is important for Bluetooth-LE accessories that deliver data at regular intervals, such as a Bluetooth heart rate belt. You enable support for using bluetooth accessories from the Background modes section of the Capabilities tab in your Xcode project. (You can also enable this support by including the UIBackgroundModes key with the bluetooth-central value in your app’s Info.plist file.) When you enable this mode, the Core Bluetooth framework keeps open any active sessions for the corresponding peripheral. In addition, new data arriving from the peripheral causes the system to wake up the app so that it can process the data. The system also wakes up the app to process accessory connection and disconnection notifications.
In iOS 6, an app can also operate in peripheral mode with Bluetooth accessories. To act as a Bluetooth accessory, you must enable support for that mode from the Background modes section of the Capabilities tab in your Xcode project. (You can also enable this support by including the UIBackgroundModes key with the bluetooth-peripheral value in your app’s Info.plist file.) Enabling this mode lets the Core Bluetooth framework wake the app up briefly in the background so that it can handle accessory-related requests. Apps woken up for these events should process them and return as quickly as possible so that the app can be suspended again.
Any app that supports the background processing of Bluetooth data must be session-based and follow a few basic guidelines:
Apps must provide an interface that allows the user to start and stop the delivery of Bluetooth events. That interface should then open or close the session as appropriate.
Upon being woken up, the app has around 10 seconds to process the data. Ideally, it should process the data as fast as possible and allow itself to be suspended again. However, if more time is needed, the app can use the
beginBackgroundTaskWithExpirationHandler:method to request additional time; it should do so only when absolutely necessary, though.
CBCentralManagerDelegate
CBCentralManager
自己要写代码
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/AboutCoreBluetooth/Introduction.html
delphi CBCentralManager CBCentralManagerDelegate
Core Bluetooth Programming Guide
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW1
https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
fetch模式
需要执行函数 application:performFetchWithCompletionHandler:
函数定义:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:performFetchWithCompletionHandler:
delphi Fetch example
http://stackoverflow.com/questions/32348081/delphi-firemonkey-ios-background-processing
http://qc.embarcadero.com/wc/qcmain.aspx?d=128968
unit uBackgroundiOS; interface uses fmx.platform.iOS,iOSapi.CocoaTypes, Macapi.ObjCRuntime, Macapi.ObjectiveC,
iOSapi.UIKit; const
UIBackgroundFetchResultNewData:NSUInteger = ;
UIBackgroundFetchResultNoData:NSUInteger = ;
UIBackgroundFetchResultFailed:NSUInteger = ; UIApplicationBackgroundFetchIntervalMinimum:NSTimeInterval = ;
UIApplicationBackgroundFetchIntervalNever:NSTimeInterval = -; type // copied from fmx.platform.iOS as it's on private declaration
id = Pointer;
SEL = Pointer;
PUIApplication = Pointer; IMP = function( self : id; cmd : SEL; Param1 : NSUInteger ) : id; cdecl; function imp_implementationWithBlock( block :id ) : IMP; cdecl; external libobjc name _PU + 'imp_implementationWithBlock';
function imp_removeBlock( anImp : IMP ) : integer; cdecl; external libobjc name _PU + 'imp_removeBlock'; procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application: PUIApplication; handler : id ); procedure initializeBackgroundFetch; function objc_msgSend(theReceiver: Pointer; theSelector: Pointer): Pointer; cdecl; varargs;
external libobjc name _PU + 'objc_msgSend'; //to test if procedure is called in background
var fecth_string_test: string; implementation procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application: PUIApplication; handler : id );
var
ahandlerimp: IMP;
begin
//Code to perform fetch HERE!!!!
fecth_string_test := 'entered background code!!'; ahandlerimp := imp_implementationWithBlock( handler ); //Create c function for block
ahandlerimp(self,_cmd, UIBackgroundFetchResultNewData); //Call c function, _cmd is ignored
imp_removeBlock(ahandlerimp); //Remove the c function created two lines up
end; procedure initializeBackgroundFetch;
Var
UIApp: UIApplication;
begin
UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication); objc_msgSend((UIApp as ILocalObject).GetObjectId,
sel_getUid('setMinimumBackgroundFetchInterval:'),
UIApplicationBackgroundFetchIntervalMinimum); class_addMethod(objc_getClass('DelphiAppDelegate') ,
sel_getUid('application:performFetchWithCompletionHandler:'),
@performFetchWithCompletionHandler,
'v@:@?');
end; end.
delphi10里
unit Macapi.Bluetooth;
TCBCentralManager = class(TOCGenericImport<CBCentralManagerClass, CBCentralManager>) end; CBCentralManagerDelegate = interface(IObjectiveC)
['{1337817E-92DE-4FA9-8CF2-E00E89125A0F}']
procedure centralManagerDidUpdateState(central: CBCentralManager); cdecl;
[MethodName('centralManager:willRestoreState:')]
procedure centralManagerWillRestoreState(central: CBCentralManager; dict: NSDictionary); cdecl;
[MethodName('centralManager:didRetrievePeripherals:')]
procedure centralManagerDidRetrievePeripherals(central: CBCentralManager; peripherals: NSArray); cdecl;
[MethodName('centralManager:didRetrieveConnectedPeripherals:')]
procedure centralManagerDidRetrieveConnectedPeripherals(central: CBCentralManager; peripherals: NSArray); cdecl;
[MethodName('centralManager:didDiscoverPeripheral:advertisementData:RSSI:')]
procedure centralManagerDidDiscoverPeripheral(central: CBCentralManager; peripheral: CBPeripheral;
advertisementData: NSDictionary; RSSI: NSNumber); cdecl;
[MethodName('centralManager:didConnectPeripheral:')]
procedure centralManagerDidConnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral); cdecl;
[MethodName('centralManager:didFailToConnectPeripheral:error:')]
procedure centralManagerDidFailToConnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral; error: NSError); cdecl;
[MethodName('centralManager:didDisconnectPeripheral:error:')]
procedure centralManagerdidDisconnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral; error: NSError); cdecl;
end;
unit System.Mac.Bluetooth;
TInternalBluetoothLEManager = class(TOCLocal, CBCentralManagerDelegate)
private
FCentralManager: CBCentralManager;
FOnDeviceDiscovered: TDeviceDiscoveredEvent;
FWaitingToDiscover: Boolean;
FIsDiscovering: Boolean;
FTimer: TInternalTimer;
FConnected: Boolean;
FOnDeviceDiscoveryTimeout: TNotifyEvent;
FLastError: Integer;
FFilterUUIDList: NSMutableArray;
FScanOptions: NSMutableDictionary;
FOnDeviceConnect: TDeviceConnectionChangeEvent;
FOnDeviceDisconnect: TDeviceConnectionChangeEvent;
procedure CreateTimer(Interval: Integer);
public
constructor Create;
destructor Destroy; override;
procedure centralManagerDidUpdateState(central: CBCentralManager); cdecl;
[MethodName('centralManager:willRestoreState:')]
procedure centralManagerWillRestoreState(central: CBCentralManager; dict: NSDictionary); cdecl;
[MethodName('centralManager:didRetrievePeripherals:')]
procedure centralManagerDidRetrievePeripherals(central: CBCentralManager; peripherals: NSArray); cdecl;
[MethodName('centralManager:didRetrieveConnectedPeripherals:')]
procedure centralManagerDidRetrieveConnectedPeripherals(central: CBCentralManager; peripherals: NSArray); cdecl;
[MethodName('centralManager:didDiscoverPeripheral:advertisementData:RSSI:')]
procedure centralManagerDidDiscoverPeripheral(central: CBCentralManager; peripheral: CBPeripheral;
advertisementData: NSDictionary; RSSI: NSNumber); cdecl;
[MethodName('centralManager:didConnectPeripheral:')]
procedure centralManagerDidConnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral); cdecl;
[MethodName('centralManager:didFailToConnectPeripheral:error:')]
procedure centralManagerDidFailToConnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral; error: NSError); cdecl;
[MethodName('centralManager:didDisconnectPeripheral:error:')]
procedure centralManagerdidDisconnectPeripheral(central: CBCentralManager; peripheral: CBPeripheral; error: NSError); cdecl;
procedure StartDiscovery(Timeout: Cardinal; const FilterUUIDList: TBluetoothUUIDsList = nil);
procedure StopDiscovery;
function ConnectTo(const APeripheral: CBPeripheral): Boolean;
function CancelConnectionTo(const APeripheral: CBPeripheral): Boolean;
procedure OnDiscoveryTimeout(Sender: TObject);
property OnDeviceDiscovered: TDeviceDiscoveredEvent read FOnDeviceDiscovered write FOnDeviceDiscovered;
property OnDeviceDiscoveryTimeout: TNotifyEvent read FOnDeviceDiscoveryTimeout write FOnDeviceDiscoveryTimeout;
property OnDeviceConnect: TDeviceConnectionChangeEvent read FOnDeviceConnect write FOnDeviceConnect;
property OnDeviceDisconnect: TDeviceConnectionChangeEvent read FOnDeviceDisconnect write FOnDeviceDisconnect;
end;
可见也用到了TInternalBluetoothLEManager和CBCentralManagerDelegate
unit System.Bluetooth;
{$IFDEF IOS}
System.Mac.Bluetooth;
{$ELSE}
http://stackoverflow.com/questions/19916513/bluetooth-central-region-monitoring-in-background-and-or-locked-no-display
2016.1.2测试,锁屏后蓝牙保持连接,为断开,就是不发送接受数据了。是不是timer停止了,给外设发送请求数据的命令移动到蓝牙接受事件里,处理完成后发送请求数据命令,而不是在timer里不停的发送,试试这种方式!!!
http://blog.csdn.net/zhuzhihai1988/article/details/30081991
Required background modes
App shares data using CoreBluetooth
App communicates using CoreBluetooth
<key>Required background modes</key>
<array>
<string>App shares data using CoreBluetooth</string>
<string>App communicates using CoreBluetooth</string>
</array>
不选bluetooth central
锁屏后蓝牙未断开连接,解锁后继续通讯,以前的曲线还在,只是锁屏后timer事件不再触发,所以停止运行了。
经过测试验证TApplicationEvent.EnteredBackground事件里, FCurrentDevice.IsConnected连接着呢。
选中bluetooth central
当蓝牙连接成功后,监测数据中,锁屏后,蓝牙断开连接了,android设备可以连接证明蓝牙确实断开了。解锁后弹出连接信息。相当于程序重新运行了,以前的曲线图也没有了。
蓝牙未连接成功,锁屏后解锁没有区别,不会自动连接。
经过测试验证TApplicationEvent.EnteredBackground事件里, FCurrentDevice.IsConnected连接着呢。
再测试,选中bluetooth central,在EnteredBackground 事件蓝牙保持了吗;不选中,进入EnteredBackground 是否断开了?如果这样就解决问题啦,结果是一样的。 FCurrentDevice.IsConnected就是true。
蓝牙连接,未监测数据,unlock screen it not restore connection.
通过TApplicationEvent事件,EnteredBackground停止计时器,WillBecomeForeground开始计时器,可以连续测试了。唯一的就是处理锁屏后数据接收的问题。以前的问题是从后台切换到前台重新连接蓝牙,现在这个问题好了,平滑切换!!不论选择bluetooth central与否,都好了。
如果在进入EnteredBackground事件里,不停止timer,不断的执行,就报错了,所以切换回来的时候会重新运行,触发oncreate和onshow事件,导致调用research方法发现设备。!!
connection,sending data,lock screen. debug mode application,see error below.
osx\Macapi.ObjectiveC.pas
class procedure TOCGenericImport<C,T>.Init(O: T; P: Pointer);
var
Imp: TOCImport;
begin// course is here
Imp := TOCImport(TRawVirtualClass.GetInstanceFromInterface(PPointer(@O)^));
{$IFDEF DEBUGUTILS}
TDebugUtils.DebugPrint('oc.instance.init', 'Initing ''%s'' with 0x%x. Old value = 0x%x',
[Imp.ClassName, IntPtr(P), IntPtr(Imp.FID)]);
{$ENDIF}
Imp.FID := P;
end;
两种可能,一种是代码写的有问题,一种是delphi的bug
DidEnterBackground
测试一下System.Mac.Bluetooth屏蔽此单元,delphi用了此单元的什么组件,屏蔽后BLE控件工程依然可以编译成功!没没用到啊。
TBluetoothLEManager
TBluetoothLE = class(TComponent)
private
protected
FManager: TBluetoothLEManager;
class constructor TBluetoothLEManager.Create;
begin
FBluetoothManagerClass := TPlatformBluetoothLEManager;
end;
TPlatformBluetoothLEManager就是System.Mac.Bluetooth里的了。最终还是用到了。
http://community.embarcadero.com/index.php/blogs/entry/spelunking-delphi-rtl-new-features-since-xe2
http://community.embarcadero.com/index.php/blogs/entry/bluetooth-le-support-in-rad-studio-xe7
UIBackgroundModes 就是XCode里的 “Required background modes”
Specifies that the app needs to continue running in the background. See UIBackgroundModes for details.
Delphi IOS 蓝牙锁屏后台运行的更多相关文章
- Delphi IOS MusicPlayer 锁屏运行学习
[weak] FMusicPlayer: TMusicPlayer; [weak]修饰, 编译器在处理这个变量的时候不会调用该变量内容的__ObjAddRef和__ObjRelease., proce ...
- 【转】ios蓝牙开发学习笔记(四)ios蓝牙应用的后台处理 -- 不错
原文网址:http://dev.ailab.cn/article-1038-220511-1.html 默认情况下,当应用进入后台或挂起时,蓝牙任务是不执行的.但是,你可以把应用声明为支持蓝牙后台执行 ...
- iOS保持App真后台运行
https://www.jianshu.com/p/d466f2da0d33 在我看来,苹果系统与安卓系统最直观的区别就是后台处理方式了吧,安卓手机一旦开启了很多app放到后台,即使前台什么也不做,就 ...
- iOS蓝牙APP常驻后台
iOS蓝牙类APP常驻后台的实现方法,经过在苹果开发者论坛询问,以及查看苹果开发者文档,最后得出正确的方法为: 1.设置plist,蓝牙权限 2.到target-capabilities-backgr ...
- iOS - Mac 锁屏快捷键设置
Mac 锁屏快捷键设置 control + shift + Eject 锁屏快捷键 如果用户要离开电脑一段时间,可以选择直接把笔记本直接合上.但是这样原先在跑的进程就会挂起或者结束,如果正在下载,那么 ...
- iOS开发——锁屏监听
公司所做的项目,锁屏监听是为了60秒后,解锁瓶后显示[手势解锁]或[指纹验证]: 第一步:AppDelegate.m 头部导入 #import <notify.h> #define Not ...
- ios GCD简单介绍 后台运行~
本从实践出发简单说明: 首先,gcd是Grand Central Dispatch的缩写,意为多线程优化技术,是苹果为多核处理优化的技术.使用简单.清晰. 多线程就分同步.异步方法如下: //异步线程 ...
- IOS开发使用GCD后台运行
什么是GCD Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法.该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中.GCD ...
- IOS 阻止 锁屏
[UIApplication sharedApplication].idleTimerDisabled=YES;不自动锁屏 idleTimerDisabled
随机推荐
- day13作业
#作业1猜年龄 , 可以让用户最多猜三次! # Auther:bing #!/usr/bin/env python age = 24 print("猜年龄") for i in r ...
- 团队作业:第五周 Alpha版本测试与发布
团队:你吼辣么大声干什么嘛 Alpha版本测试报告: bug: 修复的bug: 不能重现的bug: 无 产品设计,非bug: 在双人对战模式中,撞到墙壁会从对面的墙壁穿出,不会死 没能 ...
- make和makefile介绍
<strong>先附上一个比较简单的,测试代码用的Makefile</strong> </pre><pre code_snippet_id="463 ...
- Helix Server流媒体服务器架设教程(附Helix Server11.01下载)
现在D版的远古影视系统很流行,也很实用,但是在这之前,很多人都是用共享,或者是使用Helix Server留媒体来做电影服务器~ 虽然Helix Server流媒体服有点落伍了,不过我相信它还是有用武 ...
- 迁移 Windows 上 Oracle 11.2.0.3.0 到 Linux 上 Oracle 11.2.0.3.0
一.迁移前数据库基本信息统计 查看数据库版本 SELECT * FROM V$VERSION; /* Oracle Database 11g Enterprise Edition Release 11 ...
- vue前端开发那些事——后端接口.net core web api
红花还得绿叶陪衬.vue前端开发离不开数据,这数据正来源于请求web api.为什么采用.net core web api呢?因为考虑到跨平台部署的问题.即使眼下部署到window平台,那以后也可以部 ...
- Android开发的基础知识点
1.Android开发的四大组件: Activity:android应用程序上看到的一页. Service:运行在后台,可以其他组件交互(音乐播放器). BroadcoastReceiver:用来对外 ...
- Visual Studio 常用快捷键(一)
最近看到很多同事用 VI 来开发Ruby,Python脚本. 编辑代码全部用的是快捷键,效率很高. 其实Visual Stuido也有非常多的快捷键,熟练运用后,能大大提高工作效率. 本文介绍一些最常 ...
- WPF 自定义BarChartControl(可左右滑动的柱状图)(转)
自定义可左右滑动.拖拽滑动的平面柱状图 在做这种样式控件之前,可先浏览我之前预研的控件: A.自定义左右滑动ScrollViewer(可拖动滑动) B.自定义Bar柱状图 OK,现在说下控件具体设计过 ...
- android资源目录---assets与res/raw区别
android资源目录---assets与res/raw的不同 Android 2011-05-24 14:40:21 阅读20 评论0 字号:大中小 订阅 assets:用于存放需要打包到应用程 ...