Forum > Android

Android Module Wizard

(1/247) > >>

jmpessoa:
   Lazarus Android Module Wizard
                 "Form Designer and Components development model!"
      
   "A wizard to create JNI Android loadable module (.so) in Lazarus/Free Pascal using
   [datamodule like] Form Designer and Components!"

   Author: Jose Marques Pessoa : jmpessoa__hotmail_com

      https://github.com/jmpessoa/lazandroidmodulewizard

Please, to start:
   "readme.txt"
   "install_tutorial_ant_users.txt"
   "install_tutorial_eclipse_users.txt"

Acknowledgements: Eny and Phil for the Project wizard hints...
                  http://forum.lazarus.freepascal.org/index.php/topic,20763.msg120823.html#msg120823

                  Felipe for Android support....

                  TrueTom for Laz4Android Package (laz4android1.1-41139)...
                  https://skydrive.live.com/?cid=89ae6b50650182c6&id=89AE6B50650182C6%21149

                  Lazarus forum community!

version 0.1 - August 2013

[1]Warning: at the moment this code is just a *proof-of-concept*

I. INSTALL LAZARUS PACKAGE (laz4android1.1-41139)

   1. From lazarus IDE

      1.1 Package -> Open Package -> "lazandroidwizardpack.lpk"
   
      1.2 From Package Wizard
          1.2.1 Compile
          1.2.2 Use -> Install

II. USE

1. From Eclipse IDE

  1.1. File -> New -> Android Application Project

  1.2. From Package Explore -> src
   
       Right click your recent created package -> new -> class 
   
       Enter new class name... (ex. JNIHello)
   
       Edit class code for wrapper native methods (ex...)


--- Code: ---
                package org.jmpessoa.app1;
 
public class JNIHello {

   public native String getString(int flag);
   public native int getSum(int x, int y);

                   static {
try {
          System.loadLibrary("jnihello");           
} catch(UnsatisfiedLinkError ule) {
    ule.printStackTrace();
}
                   }
             } 


--- End code ---

  1.3. warning: System.loadLibrary("...") must match class Name lower case...
       ex. JNIHello -> "jnihello"

2. From lazarus IDE (laz4android1.1-41139)

   2.1 Project -> New Project
   2.2 JNI Android Module

2.1. From JNI Android Module set Paths
   2.1.1 Path to Eclipse Workspace
       ex. C:\adt32\eclipse\workspace
           
   2.1.2 Path to Ndk Plataforms
       ex. C:\adt32\ndk7\platforms\android-8\arch-arm\usr\lib
 
   2.1.3 Path to Ndk Toolchain 
       ex. C:\adt32\ndk7\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.4.3

2.2. From JNI Android Module select Java wrapper class for native methods.... (ex JNIHello)

2.3. OK! 

2.3.1 - Data Module Form Code:


--- Code: ---{Hint: save all files to location: C:\adt32\eclipse\workspace\App1\jni }
unit unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils;
 
type
  TAndroidModule1 = class(TDataModule)
    private
      {private declarations}
    public
      {public declarations}
  end;
 
var
  AndroidModule1: TAndroidModule1;

implementation
 
{$R *.lfm}
 
end.

--- End code ---

2.3.2. Library Code:

--- Code: ---{hint: save all files to location: C:\adt32\eclipse\workspace\App1\jni }
library jnihello;
 
{$mode delphi}
 
uses
  Classes, SysUtils, CustApp, jni, Unit1;
 
const
  curClassPathName: string='';
  curClass: JClass=nil;
  curVM: PJavaVM=nil;
  curEnv: PJNIEnv=nil;
 
type
 
  TAndroidApplication = class(TCustomApplication)
   public
     procedure CreateForm(InstanceClass: TComponentClass; out Reference);
     constructor Create(TheOwner: TComponent); override;
     destructor Destroy; override;
  end;
 
procedure TAndroidApplication.CreateForm(InstanceClass: TComponentClass; out Reference);
var
  Instance: TComponent;
begin
  Instance := TComponent(InstanceClass.NewInstance);
  TComponent(Reference):= Instance;
  Instance.Create(Self);
end;
 
constructor TAndroidApplication.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;
 
destructor TAndroidApplication.Destroy;
begin
  inherited Destroy;
end;
 
var
  Application: TAndroidApplication;
 
{ Class:     org_jmpessoa_app1_JNIHello
  Method:    getString
  Signature: (I)Ljava/lang/String; }
function getString(PEnv: PJNIEnv; this: JObject; flag: JInt): JString; cdecl;
begin
  {your code....}
  {Result:=;}
end;

{ Class:     org_jmpessoa_app1_JNIHello
  Method:    getSum
  Signature: (II)I }
function getSum(PEnv: PJNIEnv; this: JObject; x: JInt; y: JInt): JInt; cdecl;
begin
  {your code....}
  {Result:=;}
end;

const NativeMethods:array[0..1] of JNINativeMethod = (
   (name:'getString';
    signature:'(I)Ljava/lang/String;';
    fnPtr:@getString;),
   (name:'getSum';
    signature:'(II)I';
    fnPtr:@getSum;)
);

function RegisterNativeMethodsArray(PEnv: PJNIEnv; className: PChar; methods: PJNINativeMethod; countMethods:integer):integer;
begin
  Result:= JNI_FALSE;
  curClass:= (PEnv^).FindClass(PEnv, className);
  if curClass <> nil then
  begin
    if (PEnv^).RegisterNatives(PEnv, curClass, methods, countMethods) > 0 then Result:= JNI_TRUE;
  end;
end;
 
function RegisterNativeMethods(PEnv: PJNIEnv): integer;
begin
  curClassPathName:= 'org/jmpessoa/app1/JNIHello';
  Result:= RegisterNativeMethodsArray(PEnv, PChar(curClassPathName), @NativeMethods[0], Length(NativeMethods));
end;
 
function JNI_OnLoad(VM: PJavaVM; reserved: pointer): JInt; cdecl;
var
  PEnv: PPointer {PJNIEnv};
begin
  PEnv:= nil;
  Result:= JNI_VERSION_1_6;
  (VM^).GetEnv(VM, @PEnv, Result);
  if PEnv <> nil then RegisterNativeMethods(PJNIEnv(PEnv));
  curVM:= VM {PJavaVM};
  curEnv:= PJNIEnv(PEnv);
end;
 
procedure JNI_OnUnload(VM: PJavaVM; reserved: pointer); cdecl;
begin
  if curEnv <> nil then (curEnv^).UnregisterNatives(curEnv, curClass);
  curClass:= nil;
  curEnv:= nil;
  curVM:= nil;
  Application.Terminate;
  FreeAndNil(Application);
end;

exports
  JNI_OnLoad name 'JNI_OnLoad',
  JNI_OnUnload name 'JNI_OnUnload',
  getString name 'Java_org_jmpessoa_app1_JNIHello_getString',
  getSum name 'Java_org_jmpessoa_app1_JNIHello_getSum';
 
begin
  Application:= TAndroidApplication.Create(nil);
  Application.Title:= 'My Android Library';
  Application.Initialize;
  Application.CreateForm(TAndroidModule1, AndroidModule1);
end.

--- End code ---

2.4. follow the code hint: "save all files to location....."

2.5. From Lazarus IDE (laz4android1.1-41139)
     Run -> Build

III. BUILD AND RUN ANDROID APPLICATION

     1.  From Eclipse IDE

     1.1 right click your recent created project -> Run as -> Android Application

IV.  GIT HUB

     https://github.com/jmpessoa/lazandroidmodulewizard

     To facilitate follows first code release on attachment (*.rar) and some interface pictures...

     Have Fun!

jmpessoa:
Hi There,

I made some improvements on parse (and bug fix  :-[).

Now Java method signature like this:


--- Code: ---public native int getGraphics(ByteBuffer graphicsBuffer, int w, int h);
--- End code ---
   

Is handled correctly:


--- Code: ---{ Class:     org_jmpessoa_pascalgraphics_GraphicsBoard
  Method:    getGraphics
  Signature: (Ljava/nio/ByteBuffer;II)I }

function getGraphics(PEnv: PJNIEnv; this: JObject; graphicsBuffer: JObject; w: JInt; h: JInt): JInt; cdecl;
begin

end;

--- End code ---


--- Code: ---const NativeMethods:array[0..0] of JNINativeMethod = (
   (name:'getGraphics';
    signature:'(Ljava/nio/ByteBuffer;II)I';
    fnPtr:@getGraphics;)
);

--- End code ---

Follows some example picture..... and the package (*.rar)

Greetings!

https://github.com/jmpessoa/lazandroidmodulewizard

engkin:
Thank you for sharing your code.   :) It did help me learn a few things like Lazarus project wizards and  Android ARM v7 needed compiler options.

I had only one simple problem using it due to hard-coded path "C:\adt32\eclipse\workspace" in:

uformandroidproject.pas (FormAndroidProject) --> ShellTreeView1 --> Root

it worked after creating these folders and allowed my to change it to my actual folder  ;D

While working on your wizard did you have to re-build Lazarus every time you made a small change? or am I missing something?  ::)

Is it possible to use Build Modes to add compiler settings for both Arm v6 and v7 and maybe i386 to the same project using your project wizard?

Thanks again.

jmpessoa:
Hi engkin, thank you!

Actually when you modify a package you need re-install (this is
a Lazarus question)...

Hint: for install and re-intall package in Lazarus4Android close any cross-compile-android project and open a window project!

Please get  more updated version from:

https://github.com/jmpessoa/lazandroidmodulewizard

I will fix the hard path today!

Sorry, I have not learned about Build Modes... :-[

Greetings!

picstart:
With the risk of being shot as the messenger...this development is the the lifeboat for Lazarus.
Android is a significant market and is growing. Future apps will be on handheld devices. Lazarus needs a robust path to Android. Many have given up already on Lazarus sure they could spend weeks trying to get Lazarus  to compile a single app but it is smarter to go another route. The originator of this smart approach admits the reason for this direction is that they realized the futility of the existing approach. This effort is trying to bring smart back and bury the obtuse solutions offered to date. Smart work!

Navigation

[0] Message Index

[#] Next page

Go to full version