I'm trying to make an application with local service, with an example from
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Creating_Android_Services
But in my case, my service just won't fire a notification after started (nor can I be sure that the service is running). Is there any way to make sure my service is running? Since when I tried to check on device's System - Apps - Running even my app is not listed. It's like my app just died (or sleep) after it lost focus/switch to other app
Below is my simple service & notification code
function TAndroidServiceDM.AndroidServiceStartCommand(const Sender: TObject;
const Intent: JIntent; Flags, StartId: Integer): Integer;
var TheNotif: TNotification;
begin
TheNotif := Notif.CreateNotification;
try
TheNotif.Title := 'Notif Title';
TheNotif.Name := 'NotifServiceStart';
TheNotif.AlertBody := 'I''m alive!!!!';
TheNotif.FireDate := Now;
Notif.PresentNotification(TheNotif);
finally
TheNotif.Free;
end;
Result := TJService.JavaClass.START_STICKY;
end;
and this is my caller app code
procedure TfmMain.FormCreate(Sender: TObject);
var FServiceConn: TLocalServiceConnection;
begin
FServiceConn := TLocalServiceConnection.Create;
FServiceConn.StartService('unMainServiceLocation');
FServiceConn.BindService('unMainServiceLocation');
end;
procedure TfmMain.NotifReceiveLocalNotification(Sender: TObject;
ANotification: TNotification);
begin
Text1.Text :=
'Title : ' + ANotification.Title + #13#10 +
'Name : ' + ANotification.Name + #13#10 +
'Alert : ' + ANotification.AlertBody ;
end;
I tried to put a button on app and do the same thing (send notification from app) and when I pressed the button, my Text1 component shows the right thing, and the notification did appear, but not when starting my app (should've been started by the service). Service name suppose to be right since when I change the service name it got forced stopped (segmentation fault 11)
Please kindly give advice. Thanks
After having put this lines in other event (like a button click), it works fine:
FServiceConn.StartService('unMainServiceLocation');
FServiceConn.BindService('unMainServiceLocation');
The scope of your variable var FServiceConn: TLocalServiceConnection; is limited to FormCreate, meaning it will not be available outside the FormCreate procedure. Place the variable up it in the private section of the form. Don't forget to clean up on closing / destroying the form.
Related
A client of mine had the question of whether it is possible to send a push notification in the employee app if they have not entered their hours by a certain time.
Is it possible to create a service for Android and iOS apps that checks every hour if the hours of the day have been entered in the database, and if not then send a push notification?
I don't know where to start, and if it is possible. But if other apps can do it, it should be possible with this app as well.
As #SilverWarior Suggests I have created two pieces of code one makes the notifications when the app goes to the background then when the app goes to the foreground I clear Tnotificationcenter. I've used the appevent function to trigger the enterdbackground and willbecomeforground.
The Appevent code looks like this:
function TForm1.AppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
begin
case AAppEvent of
TApplicationEvent.EnteredBackground:
begin
Gethourregistration(FEmployeeNr,NOW);
if dm.MthourregistrationControl.RecordCount<1 then
begin
var Notification := NotificationCenter1.CreateNotification;
try
Notification.Name := 'message1';
Notification.AlertBody := 'You have not yet entered todays hours!';
Notification.FireDate :=Date+encodetime(19,0,0,0);
{ Send notification in Notification Center }
NotificationCenter1.ScheduleNotification(Notification);
Notification.Name := 'message2';
Notification.AlertBody := 'You have not yet entered todays hours!';
Notification.FireDate :=Date+encodetime(21,0,0,0);
{ Send notification in Notification Center }
NotificationCenter1.ScheduleNotification(Notification);
finally
Notification.Free;
end;
end;
end;
TApplicationEvent.WillBecomeForeground:
Notificationcenter1.CancelAll;
end;
end;
I use the OnCreate event for asking permission for sending notifications and trigger the AppEvent.
procedure TForm1.FormCreate(Sender: TObject);
var
AppEventSvc: IFMXApplicationEventService;
begin
if NotificationCenter1.AuthorizationStatus <> TAuthorizationStatus.Authorized then
begin
FPendingAction := Action;
NotificationCenter1.RequestPermission;
end;
if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(AppEventSvc)) then
begin
AppEventSvc.SetApplicationEventHandler(AppEvent);
end;
end;
I have tested this code and for me, this works perfectly.
First of all, I know a little bit about restarting an app. but that's when it is for windows. In this case, I need to make this for an app that is from android. I couldn't find a solution for it that works in Delphi. Just found this from #Mihai Limbășan I quote:
Perhaps you should think outside the box. Instead of futzing with the
mutex/instance logic, you could simply create another executable that
waits for your app to close then starts it again. As an added bonus,
you can later use this mechanism to, for example, update some of your
main app's binaries. It's also much easier to run it elevated instead
of maintaining different integrity levels inside the same app, etc.
But have no idea how this works or even where to start...
Every tip, code sample, or maybe other solution to restart an app will be appreciated.
EDIT
after some questions here are some pieces of code from the procedure.
First.
after you choose for example the language 'English and push the button save this happens
Inifile := TIniFile.Create(fPath);
try
Inifile.WriteString('Instelling','ip',edit5.text);
Inifile.WriteString('Instelling','user',edit6.text);
Inifile.WriteString('Instelling','pixels',edit3.text);
Inifile.WriteInteger('Instelling','language',Combobox2.ItemIndex);
fGebruiker := Edit6.Text;
fFotoformaat := StrToInt(edit3.Text);
finally
FDConnection1.Params.Values['server']:=edit5.Text;
FDConnection1.Connected := True;
inifile.free;
End;
with this code, I fill an inifile with data as you see also the item index of the Combobox for the language.
on this point i restart the app manually so the right language is chosen by this code:
procedure TfmMain.FormShow(Sender: TObject);
VAR
param : string;
inifile : tInifile;
begin
if (System.SysUtils.fileexists(fPath)) then
Begin
begin
Inifile := TIniFile.Create(fPath);
try
if not (Inifile.ReadString('Instelling','ip','default')='default') and not (Inifile.ReadString('Instelling','Gebruiker','default')='default')then
try
edit5.text := Inifile.ReadString('Instelling','ip','default');
edit6.text := Inifile.ReadString('Instelling','user','default');
Edit3.text := Inifile.ReadString('Instelling','pixel','400');
combobox2.ItemIndex := IniFile.ReadInteger('Instelling','language',1);
fpixel:= StrToInt(edit3.Text);
fuser:=edit6.text;
FDConnection1.Params.Values['server']:=edit5.Text;
taal := 'NL';
//find language settings
if combobox2.ItemIndex=0 then
begin
language:= 'NL'
end;
if combobox2.ItemIndex=1 then
begin
language:= 'ENG';
end;
if language='ENG' then
begin
vertalerENG.vertaler('ENG');
end;
end;
end;
end;
end;
the VertalerENG is a function that is fired if the language parameter is ENG and change all of the captions to English.
the problem is that nothing is changed till i restart the app.
If you want restart app programmatically,
This code work fine for me and you can set time elapse before restart app
uses
Androidapi.Helpers,Androidapi.JNI.GraphicsContentViewText,Androidapi.JNI.App,
System.DateUtils;
...
procedure RestartApp;
{$IFDEF ANDROID}
var LPM : JPackageManager;
LIntent_Start : JIntent;
LPendingIntent : JPendingIntent;
LMS : Int64;
{$ENDIF}
begin
{$IFDEF ANDROID}
LPM := TAndroidHelper.Context.getPackageManager();
LIntent_Start := LPM.getLaunchIntentForPackage(
TAndroidHelper.Context.getPackageName()
);
LIntent_Start.addFlags( TJIntent.JavaClass.FLAG_ACTIVITY_CLEAR_TOP );
LPendingIntent := TJPendingIntent.JavaClass.getActivity(
TAndroidHelper.Context,
223344 {RequestCode},
LIntent_Start,
TJPendingIntent.JavaClass.FLAG_CANCEL_CURRENT
);
LMS := DateTimeToUnix( Now, False {InputIsUTC} ) * 1000;
TAndroidHelper.AlarmManager.&set(
TJAlarmManager.JavaClass.RTC,
LMS + 10000,
LPendingIntent
);
// TAndroidHelper.Activity.finish();
Application.Terminate;
{$ENDIF }
end;
If changing the language is your only concern then i would suggest changing the locale of the application. You only need to restart the activity if you're using all the strings correctly from strings.xml
You can see it here how to change the locale of application programatically.
Change app language programmatically in Android
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I developed an android application where there is a service working in the background that job is to send notification about all rendezvous of the day.
In the main Application onCreat even i created the service form :
Application.CreateForm(TTservice, Tservice);
and i created a Tswitchbutton to start the service and to stop it :
if switchnotificationenable.IsChecked then
var
Fservice : TLocalServiceConnection;
begin
Fservice := TLocalServiceConnection.Create;
Fservice.StartService('TheService');
end;
and another code in the service's event OnstartCommande :
Result := TJService.JavaClass.START_REDELIVER_INTENT;
when debugging a violation Access pointed at the code:
Fservice.StartService('TheService');
the error normally means that what i'm calling doesn't exist i was able to access a timer that is on my service form, so i have no idea what can be the problem.
i hope you guys can help me find the solution.
i'm using Delphi XE10.2 tokyo with an sqlite database,
have a good day everyone !
Update
I found out that when i remove the file.jar of the service from the project the violation access error is gone but the service doesn't start.
-----UPDATE-----
after finding out that i cannot work with a TTimer to create my push notifications, I'm thinking about making a iTask implemented with a loop that check every 30seconds with sleep function if the system time is equal to the time given in the main application by the user
procedure TDM.AndroidServiceCreate(Sender: TObject);
var
ntf : Jnotification;
today : Ttime;
mynotification : Tnotification;
notiftime : TTime;
T : iTask;
TheINIFIle : string;
config : Tstringlist;
begin
// Loading the database path and the time given by the user in the main apps who are saved in A Ini file
TheINIFILE := TPath.Combine(TPath.GetSharedDocumentsPath ,'NotificationParams.ini');
if FileExists(TheINIFILE) then
begin
config := Tstringlist.Create;
config.loadfromfile(TheINIFILE);
notiftime := strtotime(config.Values['TimeNotification']);
TimerConnection.Database := config.Values['DatabasePath'];
TimerConnection.Connect;
// creating the iTask and giving it code that create notifications everytime the system time is equal to the notification time
if TimerCOnnection.Connected = true then
begin
T := TTask.Run(procedure
begin
while Checking = true do
begin
sleep(30000);
today := time;
with QueryForNotification do
begin
SQL.Clear;
SQL.Add('select client.entreprise, RDV.date_ntf, RDV.date_rdv, Client.num_C from client, Rdv where client.num_c = rdv.num_c and rdv.Date_Ntf = date(''now'')');
Open;
First;
while not eof do
if sametext(fieldvalues['date_ntf'], FormatDateTime('yyyy-mm-dd', now)) then
begin
MyNotification := TheNotifications.CreateNotification;
try
if sametext(formatdatetime('HH-MM',NotifTime),formatdatetime('HH-MM',today)) then
begin
MyNotification.AlertBody := 'Le RDV avec ' + FieldValues['entreprise'] + ' vous attend!' ;
TheNotifications.ScheduleNotification(MyNotification);
end;
finally
next;
MyNotification.DisposeOf;
end;
end;
end;
end;
end);
end;
end;
end;
I have an Android application and service in the same process. Write code under RAD Studio Delphi 10.1.
I need to get geographic coordinates in Android Service (that I'm doing well) and write them to the SQLite database.
And from time to time the application can (when the user needs) process the coordinates in the user interface.
When I put TConnection (any - ADO, FireDAC, UniDAC) into DataModule not even make an active connection, the service stops working, even not running the OnStartCommand event.
Monitor.bat shows no obvious errors.
Please tell me how to work with a SQLite database in Android Service and it Android Application at the same time.
I found a solution:
I updated UniDAC components for Berlin to latest version (6.3.12).
TUniConnection and TUniQuery well work with SQLite in Android Service.
Add to Project->Deployment of the host application my SQLite DB-file, Remote Path sets to ".\assets\internal\".
I hope this code will useful for you.
procedure TDM.conSQLiteBeforeConnect(Sender: TObject);
begin
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
conSQLite.Database := TPath.Combine(TPath.GetDocumentsPath, 'mybase.sqlite');
{$ENDIF}
end;
procedure TDM.conSQLiteError(Sender: TObject; E: EDAError; var Fail: Boolean);
begin
Log('--- DB error: %s:', [E.Message]);
Fail := False;
end;
function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
Log('+ START with Intent: ' + JStringToString(Intent.getAction.toString), []);
if Intent.getAction.equalsIgnoreCase(StringToJString('StopIntent')) then
begin
try
conSQLite.Disconnect;
Log('- DB disconnected', []);
except
on E: Exception do
Log('- can not to disconnect DB', [E.Message]);
end;
Log('... service to be stoped', []);
JavaService.stopSelf;
Result := TJService.JavaClass.START_NOT_STICKY; // don't reload service
end
else
begin
Log('... service started', []);
try
conSQLite.Connect;
Log('+ DB connected', []);
UniQuery.SQL.Text := 'select count(*) as ALLREC from orders';
UniQuery.Open;
if UniQuery.RecordCount > 0 then
begin
UniQuery.First;
Log('... record count: %s', [UniQuery.FieldByName('ALLREC').AsString]);
end;
UniQuery.Close;
except
on E: Exception do
Log('- can not to connect DB: %s', [E.Message]);
end;
Result := TJService.JavaClass.START_STICKY; // rerun service if it stops
end;
end;
I have struggled the same issue but I started to use TSQLConnection (dbexpress) component with TSQLQuery (dbexpress) component and these are components wrok well in Android service.
I just made an app with Delphi XE6 that receives push notifications with kinvey based on this example
When the application is running and I send a push the PushEvent handler receives it well, but when the application is closed and I press the notification it only opens my app.
Can I know which notification was pressed and get parameters from it?
Thanks in advance.
Edit:
I get a little bit closer, in my FormCreate ask for Extras:
procedure TForm1.FormCreate(Sender: TObject);
var
LIntent: JIntent;
LExtras: JBundle;
LExtrasArray: TJavaObjectArray<AndroidApi.JNI.JavaTypes.JObject>;
begin
LIntent := SharedActivity.getIntent;
try
if LIntent <> nil then
begin
LExtras := LIntent.getExtras;
if LExtras <> nil then
begin
//Now try to get the data
LExtrasArray := LExtras.KeySet.toArray;
for I := 0 to LExtrasArray.Length - 1 do
Memo1.Lines.Add(JStringToString(LExtrasArray.Items[I].toString));
end;
end;
finally
LIntent := nil;
end;
end;
With this code I get "gcm" in my memo.
So, when the notification fires my app I get this Extra available.
Now the problem is how I get info about that extra?
I tried LExtras.getString(StringToJString('message')) but this writes '' instead of the push message
Sarina DuPont answer me in her Blog
PushEvents component has a property StartupNotification for this purpose
procedure TMainForm.FormShow(Sender: TObject);
begin
if Assigned(PushEvents.StartupNotification) then
//Do something here!
//for example
//Memo.Text := PushEvents.StartupNotification.Message;
end;