繁体   English   中英

Delphi Firemonkey iOS后台处理

[英]Delphi Firemonkey iOS background processing

问题描述:

我目前正在使用Delphi XE7 Firemonkey开发Android和iOS应用程序。 此应用程序需要脱机工作,以便用户可以使用它,当手机上线时,即使应用程序在后台或手机处于待机状态,应用程序也会将所有工作发送到服务器。

Android工作方案:

正如我发现的那样,对象TThread和TTimer不起作用,因为一旦应用程序进入后台或手机停止运行它们就会停止运行。

我最终找到了这个类似于TTimer对象的库,但是当应用程序转到后台或手机处于待机状态时,它仍然有用。

https://github.com/dkstar88/AsyncTask

不幸的是,它在iOS上不起作用,因为它的行为类似于TThread和TTimer,一旦应用程序进入后台,它就会停止。

iOS试过解决方案

我尝试了几种方法,但我发现很多人都有很多关于Android的信息,但对iOS来说要少得多。

我尝试的第一件事是在plist文件中添加所需的权限来告诉iOS我想在后台执行某些操作。 我尝试了“获取”属性。

仅此一项不适用于在Android中尝试的TTimer,TThread或AsyncTask。

所以,我认为你必须告诉iOS你想在后台做一些事情以及你想在iOS中执行什么程序或代码。

我发现的最常见的代码是在这个链接(查看评论):

http://qc.embarcadero.com/wc/qcmain.aspx?d=128968

这是我使用的代码,改编自上一个链接。 它只是在备注字段中添加一行进行测试。

 unit uBackgroundiOS_2;

interface

uses iOSapi.UIKit,Macapi.ObjCRuntime,Macapi.ObjectiveC,iOSapi.CocoaTypes,FMX.Platform.iOS,iOSapi.Foundation,Macapi.Helpers,

FMX.Memo, system.SysUtils;

const UIBackgroundFetchResultNewData:NSUInteger = 0;
      UIBackgroundFetchResultNoData:NSUInteger = 1;
      UIBackgroundFetchResultFailed:NSUInteger = 2;

      UIApplicationBackgroundFetchIntervalMinimum:NSTimeInterval = 0;
      UIApplicationBackgroundFetchIntervalNever:NSTimeInterval = -1;

type
      id=Pointer;
      IMP = function( self : id; cmd : SEL; Param1 : NSUInteger ) : id; cdecl;

Var UIApp : UIApplication;
    memo: TMemo;

function imp_implementationWithBlock( block :Pointer ) : IMP; cdecl; external libobjc name  _PU + 'imp_implementationWithBlock';
function imp_removeBlock( anImp : IMP ) : integer; cdecl; external libobjc name _PU + 'imp_removeBlock';
function objc_addClass(Cls: Pointer): Integer; cdecl; external libobjc name _PU + 'objc_addClass';

procedure performFetchWithCompletionHandler(self:id; _cmd: SEL;application:id; handler:id);


procedure Init(p_memo: Tmemo);

implementation

procedure Init(p_memo: Tmemo);
var
  Res: Integer;
begin
{
Info:
use .\plist\BackgroundOPs.info.plist from Project Main Pfad and copy to Info.plist

include the Keys:
<key>UIBackgroundModes</key>
<array>
 <string>fetch</string>
 <string>remote-notification</string>
 <string>newsstand-content</string>
</array>
}
UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);

objc_msgSend((UIApp as ILocalObject).GetObjectId,sel_getUid('setMinimumBackgroundFetchInterval:'),UIApplicationBackgroundFetchIntervalMinimum);
Res := class_addMethod( objc_getClass('DelphiAppDelegate') , sel_getUid('application:performFetchWithCompletionHandler:'), @performFetchWithCompletionHandler,'v@:@?');

memo := p_memo;
end;



procedure performFetchWithCompletionHandler(self:id; _cmd: SEL;application:id; handler:id);
{
Using your device you can fire application:performFetchWithCompletionHandler with the following steps:
Put your app in the Background state.
Lock your device and wait 5 minutes. (I know, it's a waste of time, get some coffee)
Unlock your device, this is will fire the method.
}
var
  ahandlerimp: IMP;
begin
  try
    // here your code max. 30 Sec.
    Memo.Lines.Add(FormatDateTime('hh:nn:ss', Now));

    ahandlerimp := imp_implementationWithBlock(handler);
    ahandlerimp(self,_cmd,UIBackgroundFetchResultNewData); // return the Do- code
    imp_removeBlock(ahandlerimp);
  except
  end;
end;

end.

这在iOS 8.4.1的iphone 4中不起作用。 我把手机待了一段时间,当我检查应用程序时,备忘录字段是空白的。

什么可能是错的? 我在这里有点死路一条。

非常感谢!

PS:在我原来的帖子里我放了更多的链接和来源(包括其他stackoverflow帖子),但遗憾的是我只留下了最相关的两个,因为我没有10个声望要求发布更多。


混合来自这两个例子的代码我做了以下单元:

http://qc.embarcadero.com/wc/qcmain.aspx?d=128968 (参见注释) 从delphi调用目标C代码块

unit uBackgroundiOS;

interface

uses fmx.platform.iOS,iOSapi.CocoaTypes, Macapi.ObjCRuntime, Macapi.ObjectiveC,
     iOSapi.UIKit;

const
  UIBackgroundFetchResultNewData:NSUInteger = 0;
  UIBackgroundFetchResultNoData:NSUInteger = 1;
  UIBackgroundFetchResultFailed:NSUInteger = 2;

  UIApplicationBackgroundFetchIntervalMinimum:NSTimeInterval = 0;
  UIApplicationBackgroundFetchIntervalNever:NSTimeInterval = -1;

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;

  //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
  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;
  Interval: Pointer;
begin
  UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication);

  Interval := objc_msgSend((UIApp as ILocalObject).GetObjectId,
                            sel_getUid('setMinimumBackgroundFetchInterval:'));
//               Interval);
  class_addMethod( objc_getClass('DelphiAppDelegate') ,
                  sel_getUid('application:performFetchWithCompletionHandler:'),
                  @performFetchWithCompletionHandler,
                  'v@:@?'
  );
end;

end.

此代码不起作用。 我在应用程序启动时调用initializeBackgroundFetch。 我确信我做错了什么,但无法弄清楚它是什么。

另外我注意到我的应用程序没有出现在iPhone设置的后台允许应用程序中,是否应该出现? 我在info.plist文件中添加了以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
[...]
    <key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>remote-notification</string>
        <string>newsstand-content</string>
    </array>
</dict>
</plist>

有任何想法吗?

iOS工作解决方案

我终于让它在delphi 10 Seattle下工作了(你需要这个版本,我已经尝试过XE7但是没有用,我还没试过xe8)。 以下是步骤:

1-项目>选项>版本信息。 检查你需要的UIBackgroundModes(我用过Fetch)

2-这是我使用的代码:

unit uBackgroundiOS;

interface

uses fmx.platform.iOS,iOSapi.CocoaTypes, Macapi.ObjCRuntime, Macapi.ObjectiveC,
     iOSapi.UIKit;

const
  UIBackgroundFetchResultNewData:NSUInteger = 0;
  UIBackgroundFetchResultNoData:NSUInteger = 1;
  UIBackgroundFetchResultFailed:NSUInteger = 2;

  UIApplicationBackgroundFetchIntervalMinimum:NSTimeInterval = 0;
  UIApplicationBackgroundFetchIntervalNever:NSTimeInterval = -1;

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.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM