Delphi Android programming
Sunday, November 3, 2013
How to create Android services using Delphi XE5 using TTimer
Delphi XE5 does not provide the ability to create Android services, yet. However, there is a simple workaround: If you put a TTimer on a form, this form and this TTimer will also continue to run after switching to another app, or after closing the screen. This way, you can make a simple app that does something even when not in use.
Saturday, November 2, 2013
Delphi for Android uses 0-based strings
Delphi handles strings differently when compiling for Windows and Android.
Windows has 1-based strings, i.e. the first character in a string is s[1].
Android has 0-based strings, i.e. the first character in a string is s[0].
Also, you should expect, that future versions of Delphi will not allow you to write this code:
s[1]:='a';
Android apps start slowly? Here is the trick
When you run an Android app, it will be a slow startup because of the Android technology choices. The local emulator is an emulator, which means slow. If you attach a phone for development, the app still needs to be packaged, the old app needs to be uninstalled, the new version needs to be installed etc. All this takes time.
Fortunately, there is a solution: You can make your app compile for both Android and Windows, and debug most functionality as a Windows app. These guidelines can help you:
Fortunately, there is a solution: You can make your app compile for both Android and Windows, and debug most functionality as a Windows app. These guidelines can help you:
- Put all Android-specific code into units that have a name that starts with "Android". For instance, if you want to send an SMS, put the code for that into an AndroidSms.pas unit.
- Use {$IFDEF ANDROID} for code that you want to execute only when deployed on Android.
- Exclude Android* units from the dpr file
Here is an example of a uses-clause that compiles with both Android and Windows:
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
{$IFDEF ANDROID}
AndroidSms,
{$ENDIF}
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls;
Here is an example of some code that does one thing on Android, and another thing when compiling to Windows:
procedure TForm2.SendSMS (target,messagestr:string);
begin
{$IFDEF ANDROID}
AndroidSms.SendSms(target,messagestr);
{$ELSE}
Memo1.Lines.Add (target+': '+messagestr);
{$ENDIF}
end;
As you can see in this last example, the Windows version will visualize to the programmer, that the app was meant to send an SMS at this point, instead of actually doing it. This speeds up testing a lot.
Friday, November 1, 2013
Fetching files using https (SSL) using Delphi for Android
Copy & paste solution, which logs in, supports https and returns the result as one large string:
uses
Classes, SysUtils,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
IdSSLOpenSSL;
function HttpsAuthGet(Url, Username, Password: string):string;
var
ssl: TIdSSLIOHandlerSocketOpenSSL;
http: TIdHTTP;
begin
http := TIdHttp.Create(nil);
try
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
http.IOHandler := ssl;
http.Request.BasicAuthentication:=True;
http.Request.Username := Username;
http.Request.Password := Password;
Result:=http.Get(Url);
if (http.ResponseCode<200) or (http.ResponseCode>=300) then
raise Exception.Create(http.ResponseText);
finally
FreeAndNil(ssl);
end;
finally
FreeAndNil(http);
end;
end;
uses
Classes, SysUtils,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
IdSSLOpenSSL;
function HttpsAuthGet(Url, Username, Password: string):string;
var
ssl: TIdSSLIOHandlerSocketOpenSSL;
http: TIdHTTP;
begin
http := TIdHttp.Create(nil);
try
ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
http.IOHandler := ssl;
http.Request.BasicAuthentication:=True;
http.Request.Username := Username;
http.Request.Password := Password;
Result:=http.Get(Url);
if (http.ResponseCode<200) or (http.ResponseCode>=300) then
raise Exception.Create(http.ResponseText);
finally
FreeAndNil(ssl);
end;
finally
FreeAndNil(http);
end;
end;
Download file to Android app using Delphi
This is a very simple one, because it works the same way as it did with Delphi for Windows:
function HttpGet(const url: string): string;
var
HTTP: TIdHTTP;
begin
HTTP := TIdHTTP.Create(nil);
try
Result:=http.Get(url);
finally
FreeAndNil (http);
end;
end;
Where did PAnsiChar go with Delphi XE5 and Android?
Olaf Monien has written about this here.
Sunday, October 27, 2013
How to fetch SMS messages from the Android inbox using Delphi
The code speaks for itself:
uses
SysUtils,
FMX.Helpers.Android,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.Net,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.Telephony;
function FetchSms:string;
var
cursor: JCursor;
uri: Jnet_Uri;
address,person,msgdatesent,protocol,msgread,msgstatus,msgtype,
msgreplypathpresent,subject,body,
servicecenter,locked:string;
msgunixtimestampms:int64;
addressidx,personidx,msgdateidx,msgdatesentidx,protocolidx,msgreadidx,
msgstatusidx,msgtypeidx,msgreplypathpresentidx,subjectidx,bodyidx,
servicecenteridx,lockedidx:integer;
begin
uri:=StrToJURI('content://sms/inbox');
cursor := SharedActivity.getContentResolver.query(uri, nil, nil,nil,nil);
addressidx:=cursor.getColumnIndex(StringToJstring('address'));
personidx:=cursor.getColumnIndex(StringToJstring('person'));
msgdateidx:=cursor.getColumnIndex(StringToJstring('date'));
msgdatesentidx:=cursor.getColumnIndex(StringToJstring('date_sent'));
protocolidx:=cursor.getColumnIndex(StringToJstring('protocol'));
msgreadidx:=cursor.getColumnIndex(StringToJstring('read'));
msgstatusidx:=cursor.getColumnIndex(StringToJstring('status'));
msgtypeidx:=cursor.getColumnIndex(StringToJstring('type'));
msgreplypathpresentidx:=cursor.getColumnIndex(StringToJstring('reply_path_present'));
subjectidx:=cursor.getColumnIndex(StringToJstring('subject'));
bodyidx:=cursor.getColumnIndex(StringToJstring('body'));
servicecenteridx:=cursor.getColumnIndex(StringToJstring('service_center'));
lockedidx:=cursor.getColumnIndex(StringToJstring('locked'));
while (cursor.moveToNext) do begin
address:=JStringToString(cursor.getString(addressidx));
person:=JStringToString(cursor.getString(personidx));
msgunixtimestampms:=cursor.getLong(msgdateidx);
msgdatesent:=JStringToString(cursor.getString(msgdatesentidx));
protocol:=JStringToString(cursor.getString(protocolidx));
msgread:=JStringToString(cursor.getString(msgreadidx));
msgstatus:=JStringToString(cursor.getString(msgstatusidx));
msgtype:=JStringToString(cursor.getString(msgtypeidx));
msgreplypathpresent:=JStringToString(cursor.getString(msgreplypathpresentidx));
subject:=JStringToString(cursor.getString(subjectidx));
body:=JStringToString(cursor.getString(bodyidx));
servicecenter:=JStringToString(cursor.getString(servicecenteridx));
locked:=JStringToString(cursor.getString(lockedidx));
Result:=IntToStr(trunc(msgunixtimestampms/1000))+' '+address+' '+body;
end;
end;
uses
SysUtils,
FMX.Helpers.Android,
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.Net,
Androidapi.JNI.JavaTypes,
Androidapi.JNI.Telephony;
function FetchSms:string;
var
cursor: JCursor;
uri: Jnet_Uri;
address,person,msgdatesent,protocol,msgread,msgstatus,msgtype,
msgreplypathpresent,subject,body,
servicecenter,locked:string;
msgunixtimestampms:int64;
addressidx,personidx,msgdateidx,msgdatesentidx,protocolidx,msgreadidx,
msgstatusidx,msgtypeidx,msgreplypathpresentidx,subjectidx,bodyidx,
servicecenteridx,lockedidx:integer;
begin
uri:=StrToJURI('content://sms/inbox');
cursor := SharedActivity.getContentResolver.query(uri, nil, nil,nil,nil);
addressidx:=cursor.getColumnIndex(StringToJstring('address'));
personidx:=cursor.getColumnIndex(StringToJstring('person'));
msgdateidx:=cursor.getColumnIndex(StringToJstring('date'));
msgdatesentidx:=cursor.getColumnIndex(StringToJstring('date_sent'));
protocolidx:=cursor.getColumnIndex(StringToJstring('protocol'));
msgreadidx:=cursor.getColumnIndex(StringToJstring('read'));
msgstatusidx:=cursor.getColumnIndex(StringToJstring('status'));
msgtypeidx:=cursor.getColumnIndex(StringToJstring('type'));
msgreplypathpresentidx:=cursor.getColumnIndex(StringToJstring('reply_path_present'));
subjectidx:=cursor.getColumnIndex(StringToJstring('subject'));
bodyidx:=cursor.getColumnIndex(StringToJstring('body'));
servicecenteridx:=cursor.getColumnIndex(StringToJstring('service_center'));
lockedidx:=cursor.getColumnIndex(StringToJstring('locked'));
while (cursor.moveToNext) do begin
address:=JStringToString(cursor.getString(addressidx));
person:=JStringToString(cursor.getString(personidx));
msgunixtimestampms:=cursor.getLong(msgdateidx);
msgdatesent:=JStringToString(cursor.getString(msgdatesentidx));
protocol:=JStringToString(cursor.getString(protocolidx));
msgread:=JStringToString(cursor.getString(msgreadidx));
msgstatus:=JStringToString(cursor.getString(msgstatusidx));
msgtype:=JStringToString(cursor.getString(msgtypeidx));
msgreplypathpresent:=JStringToString(cursor.getString(msgreplypathpresentidx));
subject:=JStringToString(cursor.getString(subjectidx));
body:=JStringToString(cursor.getString(bodyidx));
servicecenter:=JStringToString(cursor.getString(servicecenteridx));
locked:=JStringToString(cursor.getString(lockedidx));
Result:=IntToStr(trunc(msgunixtimestampms/1000))+' '+address+' '+body;
end;
end;
Subscribe to:
Posts (Atom)