Recent

Author Topic: Android Module Wizard  (Read 532185 times)

jmpessoa

  • Hero Member
  • *****
  • Posts: 1481
Re: Android Module Wizard
« Reply #1200 on: November 22, 2019, 07:32:41 am »
Ok, kordal!

I will try your solution!

Thank you!

[Edited]
    Commited!!!
« Last Edit: November 23, 2019, 03:57:44 am by jmpessoa »
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

m4u_hoahoctro

  • Full Member
  • ***
  • Posts: 160
Re: Android Module Wizard
« Reply #1201 on: January 06, 2020, 11:48:00 am »
@jmpessoa

Can you write a guide on how to make an own component into lamw ?

I have a while on using flutter and its experience on app seem be more native than lamw's, but making an app with lamw still be easier, hope we can have more components for use :) (May i will contribute for some examples of IoT/Arduino/ARM/AVR :) )

kordal

  • New Member
  • *
  • Posts: 18
Re: Android Module Wizard
« Reply #1202 on: January 09, 2020, 01:26:31 am »
Directories & Files:
...\lazandroidmodulewizard\android_bridges\  - directory to Pascal components realization
register_ ... .pas - component registration files (if uses LAMW wizard, edited automaticly)
*.lrs - icon files of components

..\lazandroidmodulewizard\android_wizard\smartdesigner\java\ - directory to Java components realization
*.create - component initialization code
*.java - component main code
*.native - component event procedures
*.relational - list of *.java files (dependencies), if used in the main module java component

How to start?
  • Lazarus IDE -> Tools -> [LAMW] Android Module Wizard -> New jComponent Create
  • Click right mouse button

Note: When you write bridge functions in Pascal, pay attention to the names of functions in Java code and how they are called in JNI. A prerequisite is the presence of signatures for functions that change depending on the input / output parameters (arguments).

Example (the example is not complete):
jMyComponent.java
Code: Java  [Select]
  1. // package org.lamw...; // changes automatically  
  2. //
  3. // skip two lines
  4.  
  5. import android.os.Bundle;
  6. // other imports
  7. // see https://developer.android.com/reference
  8.  
  9. public class jMyComponent {
  10.     // Java-Pascal Interface
  11.     private long     pascalObj   = 0;    // Pascal Object
  12.     private Controls controls    = null; // Java/Pascal [events] Interface ...
  13.     private Context  context     = null;
  14.  
  15.     // constructor
  16.    public jMyComponent(Controls _Ctrls, long _Self /*, other parameters*/ ) {
  17.                 context   = _Ctrls.activity;
  18.                 controls  = _Ctrls;
  19.                 pascalObj = _Self;
  20.                
  21.    }
  22.  
  23.   // destructor
  24.   public void jFree() {
  25.      // free local objects...
  26.   }
  27.  
  28.   public int Sum(int a, int b) {
  29.      return a + b;
  30.   }
  31.  
  32. }
  33.  

MyComponent.pas
Code: Pascal  [Select]
  1.   // ...
  2. type  
  3.   jMyComponent = class(...)
  4.     // initialization code
  5.     // ...
  6.     function Sum(a, b: Integer): Integer;
  7.   end;
  8.  
  9.   function jMyComponent.Sum(a, b: Integer): Integer;
  10.   begin
  11.     if FInitialized then
  12.       Result := jMyComponent_Sum(FjEnv, FjObject, a, b);
  13.   end;
  14.  
  15.   // JNI implementation
  16.   function jMyComponent_Sum(env: PJNIEnv; _jmycomponent: JObject; _a, _b: Integer): Integer;
  17.   var
  18.     jParams: array[0..1] of JValue;
  19.     jMethod: JMethodID = nil;
  20.     jCls   : JClass = nil;      
  21.   begin
  22.     jParams[0].i := _a;
  23.     jParams[1].i := _b;
  24.     jCls := env^.GetObjectClass(env, _jmycomponent);
  25.     jMethod := env^.GetMethodID(env, jCls, 'Sum', '(II)I'); // function name 'Sum', signature (I - integer, I - integer) result Integer  
  26.     Result := env^.CallIntMethodA(env, _jmycomponent, jMethod, @jParams);
  27.     // env^.CallVoidMethodA(env, _jmycomponent, jMethod, @jParams);  // no result
  28.     // env^.CallVoidMethod(env, _jmycomponent, jMethod);  // no result, no params
  29.     // env^.CallFloatMethodA(env, _jmycomponent, jMethod, @jParams);  // result float, with params
  30.    
  31.    // See more And_jni.pas & other components
  32.     env^.DeleteLocalRef(env, jCls);                                  
  33.   end;
  34.  
  35.   // signatures
  36. (*  
  37.  
  38.   Z - Boolean
  39.   B - Byte
  40.   I - Integer
  41.   F - Float (Single)
  42.   V - Void (no result)
  43.   L - java Object
  44.   [ - array, ex [I - integer array, [F - float array, etc.
  45.  
  46. *)
  47.  

To view signatures of compiled java files, you can use, for example, JCSign tool.

Official help:

Quote
"LAMW: Lazarus Android Module Wizard"

   Author: Jose Marques Pessoa

      https://github.com/jmpessoa/lazandroidmodulewizard

:: How to Create JNI Bridge Component code::
 
1. LAMW Component Model: 

   ::  jControl: No GUI Control     

       hint: you can use composition or inheritance model here....

   ::  jVisualControl: GUI Control

       warning:  you MUST use inheritance model here.....

2. Creating a new component:
     
   2.1. Right click Java tab:

   2.1. Insert a new [wrapper] java class  jControl/jVisualControl from template;

        hint1. Alternatively, you can paste you java code [template compatible] from clipboard!

        hint2. Alternatively, you can import a "JAR" file and selec a class [at the moment, only for no visual  control]!

        hint3: You can also use the demo AppTryCode3 to produce a complete [wrapper]  java class !

       hint4. you do not need to build the "perfect" component now .... later you can add more methods, events and properties! [sections 3 e 4 bellow]

        warning/important: All "imports" from "Controls.java" template  and new "imports" from you java class code
                   will  be researched to try write the correct JNI methods signatures.....

                     
   2.2. Rename [and extends] the new class [and constructor], write some custom field, methods, etc...
        [for "JAR" imported class this task is automated! ]
       
        guideline: please, preferentially init your news params names with "_", ex: int _flag, String _hello ...
         
        hint1: Only public methods will be translated to pascal [bridge] code.
        hint2:  use the  mask  /*.*/   to make a public method invisible for the parse [ex.  /*.*/public myfunctio() {....} ] 

   2.3. Select all  the new java class code and right click it [java tab] .
     
       hint1:  if have only one java class code you do not need select it! just right click it!
       hint2. save your java class source code in LAMW folder "......\android_wizard\smartdesigner\java" :

        warning:  the  LAMW java to pascal convert dont support complex/generic types like  "java.util.Map<,>" ,  "java.util.Set<>" etc..
       So, we need re-write  the method signature [by hand] for primitives data/array type....

      But simple java Object param [or return]  is ok   [including array!!!]!
     
      public void SetImage(Bitmap _image) {     //<<----  OK!
             this.setImage(_image);
      }
 
     public Bitmap GetImage(Bitmap _image) {     //<<---- OK!
             return this.getImage();
      }

       warning/important: All "imports" from "Controls.java" template  and new "imports" from you java class code
                   will  be researched to try write the correct JNI methods signatures.....
     
   2.4. Popup Menu: Select "Write [Draft] Pascal jControl/jVisualControl Interface".
 
   2.5. Right click Pascal Tab  and select "Register Component..." from  Popup Menu;

          warning: Mac users: please, you must copy the console app "lazres" [lazarus/tools] to the folder
          ".../LazAndroidWizard/ide_tools";

   2.6. [Dialog]:  select a 16x16 PNG icon file;

   2.7.  [Dialog]:  open a "register_*.pas" file (ex. "register_extra.pas"); **

      hint: you can select "register_template.pas" to write a custom register file,
              but, then,  you must insert it into  "tfpandroidbridge_pack.lpk".

   2.8. Ok. You got you DRAFT pascal component JNI stuff! Please, look in the folder   "..../LazAndroidWizard/android_bridges"
         directory:
         
        :: *.pas           <--- open and fix/complete the pascal code with your others events/properties/methods/variables/overload!

        :: *_icon.lrs    <--- new icon resource
        :: register_extras.pas   <--- updated!  by default, the new component will be include there!

   2.9. [Lazarus IDE Menu]: Package -> Open Package File (*.lpk) --> "tfpandroidbridge_pack.pas" in folder 
         "....../LazAndroidWizard/android_bridges".

   2.10. [Package Wizard]: Compile --->> Use ---> Install.

            Warning: to compile/install/reinstall a LAMW package in  Lazarus/Laz4Android [windows],
               please, open a "dummy" pure windows project.... you MUST always close the cross compile project!
   
   2.11. Wait .... Lazarus re-building ...

   2.12. The new component  is on "Android Bridges Extra" [or other...] palette!.
   
   3. Added more methods to your component   

   3.1.  write new method to  your ".java" code
           ex.
                 public void SetFoo(int _foo) {
                       mFoo = _foo;
                 }
                  public int GetFoo() {
                        return mFoo;
                  }

   3.1.  In java tab write a draft java class code to wrapper the [new] methods;

           class jMyComponent {

                 public void SetFoo(int _foo) {
                       mFoo = _foo;
                 }
                  public int GetFoo() {
                        return mFoo;
                  }
          }                 
           
    3.2   Right click the Java tab and select "Write [draft] complementary Pascal Interface"

    3.4   Copy the the pascal interface code to your component unit!!!
       
    4. Added "native" [events] methods to your component

    4.1.  write the native method "call" to to  your ".java" code    [study some LAMW code as example!]

               ex1:   [from jSpinner.java]
 
                controls.pOnSpinnerItemSelected(pascalObj,position,caption);   //return void

              ex2:   [fiction...]
                int  i = controls.pOnSpinnerItemSelected(pascalObj,position,caption);   //return int             
 
              ex3:   [fiction...]
                int[] v;
                 v = controls.pOnSpinnerItemSelected(pascalObj,position,caption);   //return int[]     
                 for (int i = 0; i < v.length; i++) {
                     //Log.i("v["+i+"]", ""+v);     //do some use...
                 }         
               
              ex4:   [fiction...]
                String[] s;
                 s = controls.pOnSpinnerItemSelected(pascalObj,position,caption);   //return String[]               
                for (int i = 0; i < s.length; i++) {
                     //Log.i("s["+i+"]", ""+s);     //do some use...
                 }         
 
    4.2.  write the native method signature to your [component] ".native" file    [study some LAMW code as example!]
           ex1.    [from jSpinner.native]       
              public native void pOnSpinnerItemSelected(long pasobj, int position, String caption);

           ex2.    [fiction...]       
              public native int pOnSpinnerItemSelected(long pasobj, int position, String caption);

           ex3.    [fiction...]       
              public native int[] pOnSpinnerItemSelected(long pasobj, int position, String caption);

           ex4.    [fiction...]       
              public native String[] pOnSpinnerItemSelected(long pasobj, int position, String caption);

    4.3.  In java tab write a draft java class code to wrapper the the native [one line!] method;
         
           class jMyComponent {

                public native void pOnMyComponentItemSelected(long pasobj, int position, String caption); //MyComponent

          }                 

         NOTE: the  "//MyComponent" signs the part of the method name that will be overshadowed in the nomination of the property.
                            ex.  FOnItemSelected   [ not FOnMyComponentItemSelected  ]   

    4.4   Right click the Java tab and select "Write [draft] complementary Native Method Pascal Interface"

    4.5   Copy the the pascal interface code [generated] to your component unit [mycomponent.pas] and to "Laz_And_Controls_Events.pas"!!!

    Congratulations!!!     

« Last Edit: January 10, 2020, 12:20:13 am by kordal »

Mongkey

  • New Member
  • *
  • Posts: 12
Re: Android Module Wizard
« Reply #1203 on: January 10, 2020, 11:36:35 am »
Thanks bro, your tools are awesome!

cant wait for new advanced cool bridge :D
« Last Edit: January 10, 2020, 12:04:01 pm by Mongkey »