Problembeschreibung:Delphi Firemonkey iOS Hintergrundverarbeitung
Ich bin derzeit die Entwicklung und Android und iOS-Anwendung mit Delphi XE7 Firemonkey. Diese App muss offline arbeiten, damit der Benutzer damit arbeiten kann und wenn das Telefon online geht, sendet die App die gesamte Arbeit an die Server, selbst wenn die App im Hintergrund läuft oder das Telefon im Standby-Modus ist.
Android-Arbeitslösung:
Als ich herausgefunden habe, Objekte TThread und TTimer nicht funktioniert, wie sie ausgeführt wird gestoppt, sobald die App in den Hintergrund geht oder das Telefon zu stehen geht.
Ich fand diese Bibliothek für Android, die wie ein TTimer-Objekt funktioniert, aber es funktioniert immer noch, wenn die App in den Hintergrund geht oder das Telefon in Bereitschaft ist.
https://github.com/dkstar88/AsyncTask
Leider ist es nicht auf iOS arbeiten, wie es wie TThread und TTimer verhält und es stoppt, sobald die App in den Hintergrund geht.
iOS versucht Lösungen
ich verschiedene Ansätze ausprobiert, aber ich fand, dass eine Menge Leute eine Menge Informationen über Android hat aber viel weniger für iOS.
Das erste, was ich ausprobiert habe, war das Hinzufügen der PLIST-Datei die erforderlichen Berechtigungen, iOS zu sagen, dass ich etwas im Hintergrund tun möchte. Ich habe die Eigenschaft "fetch" versucht.
Dies allein funktioniert nicht mit TTimer, TThread oder AsyncTask in Android versucht.
Also dachte ich, du musst iOS sagen, dass du etwas im Hintergrund tun willst UND welche Prozedur oder welchen Code iOS im Backgroud ausführen soll.
Der promsinig Code Ich war (siehe Kommentare) in diesen Links gefunden:
http://qc.embarcadero.com/wc/qcmain.aspx?d=128968
Hier ist der Code ich aus dem vorherigen Link angepasst verwendet. Es fügt einfach eine Zeile zum Testen in ein Memofeld ein.
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,'[email protected]:@?');
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.
Dies funktioniert nicht in meinem iPhone 4 mit iOS 8.4.1. Ich ließ das Telefon für eine Weile stehen und als ich die App überprüfte, war das Memofeld leer.
Irgendeine Idee von was könnte falsch sein? Ich bin hier ein bisschen eine Sackgasse.
Vielen Dank!
PS: in meinem ursprünglichen Beitrag habe ich mehr Links und Quellen (einschließlich andere stackoverflow Beiträge), aber leider habe ich nur die relevantesten zwei, weil ich nicht die 10 Ruf benötigt, um mehr zu posten.
aus diesen beiden Beispielen Misch Code habe ich die folgende Einheit:
http://qc.embarcadero.com/wc/qcmain.aspx?d=128968 (siehe Kommentare) Calling objective C code block from delphi
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,
'[email protected]:@?'
);
end;
end.
Dieser Code funktioniert nicht. Ich rufe initializeBackgroundFetch beim Start der Anwendung auf. Ich bin mir sicher, dass ich etwas falsch mache, aber nicht herausfinden kann, was es ist.
Auch ich habe bemerkt, dass meine Anwendung nicht im Hintergrund erscheint Anwendungen in den iPhone-Einstellungen zulassen, sollte es angezeigt werden? Ich fügte folgendes in die info.plist Datei hinzu:
<?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>
Irgendwelche Ideen?
Weitere Quellen: iOS Hintergrund Eigenschaften: [link] (http://delphi.radsoft.com .au/2013/10/providering-background-services-support-to-your-ios-apps-with-delphi /) Link zu StackOverflow: [link] (https://stackoverflow.com/questions/24168144/ delphi-firemonkey-ios-background-fetch) Objective-C Beispiele: [link] (http://hayageek.com/ios-background-fetch/) [li nk] (https://possiblemobile.com/2013/09/ios-7-background-fetch/) –
Auch versucht dies [link] (http://codeverge.com/embarcadero.delphi.ios/does-delphi-i- for-ios-support-complete-b/1095555) Aber löst "Externe Ausnahme 0". –
aktualisiert die Hauptpost mit neuen Code –