Thursday, October 1, 2015

Android Module Wizard

 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: [Select]

                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();
}
                   }
             } 

  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: [Select]
{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.

2.3.2. Library Code:
Code: [Select]
{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.

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!
« Last Edit: December 21, 2014, 07:01:00 pm by jmpessoa »
 http://forum.lazarus.freepascal.org/index.php/topic,21919.0.html