首发在

①FireMonkey[移动开发] 16523232

欢迎使用 FMX 开发手机程序的高手来访。

注意:如果您看了本文,翻译了 JNI,请发布到本群共享一份。
不同意本规定的,请立即删除本文。
凡是看了的,就表示您同意本规定。

请大家从群共享下载(①FireMonkey[移动开发] 16523232)
某某某 源代码 带调用非官方 JNI 示例.zip
里头的
Androidapi.JNI.TelephonyGemini.pas
就是我自己转的接口。

或者
重启你的手机 源代码 V1.1
里头也有一些转好的接口。

转换前需要先找到对应的 JAVA 定义文件。最好是 *.java 的。

而且要记住路径(相对于 sources\版本 的路径,下面的例子中自己参详)。
如果是第三方的 JAR 加入到 DELPHI 的 DEX 后 他也是有路径的。他的 JAVA 文件中的包名就是个路径。

一个接口对象分四部分完成。

type

//第一部分,预定义接口对象。后面的注释大家最好都加上。
{Class forward declarations}
JPhoneNumberFormattingTextWatcherEx = interface;//com.mediatek.telephony.PhoneNumberFormattingTextWatcherEX
JTelephonyManagerMTKGemini = interface;//com.mediatek.telephony.TelephonyManagerEx
JSmsManagerGeminiMTK = interface;//android.telephony.GeminiSmsManager

//第二部分,定义接口的类成员(类方法和属性)的对象。
JPhoneNumberFormattingTextWatcherExClass = interface(JObjectClass)
['{0A3E7ECF-F81E-4062-9487-032C3E209466}']
{Methods}
end;

//第三部分,定义接口的普通成员的对象。
[JavaSignature('com/mediatek/telephony/PhoneNumberFormattingTextWatcherEx')]
JPhoneNumberFormattingTextWatcherEx = interface(JObject)
['{752F5521-E746-449E-A9A8-7AE73FF63B05}']
{Methods}
end;
//第四部分,定义接口的构造器。
TJPhoneNumberFormattingTextWatcherEx = class(TJavaGenericImport<JPhoneNumberFormattingTextWatcherExClass, JPhoneNumberFormattingTextWatcherEx>) end;

其中
[JavaSignature('com/mediatek/telephony/PhoneNumberFormattingTextWatcherEx')]
[JavaSignature('android/telephony/gemini/GeminiSmsManager')]
这个必须注意,路径千万不能错。路径不包括扩展名,也不包括 sources\版本 目录。

但是类对象在 DELPHI 中的名称可以自己决定,当然一致最好。

然后要注意,接口中 GUID 请一定要用一个新的。用 CTRL+SHIFT+G 即可产生。

打开你的 XXX.java 文件(一般在 PlatformSDKs\adt-bundle-windows-x86-20130522\sdk\sources\版本 下面)。

查看下他的类型。如果是普通的类 class,那么我们称之为 JObject
如果是 interface ,那么我们称之为 IJavaInstance 。

在定义他们的 第二 和 第三 部分的时候,他们的 父类(基类) 就要做相应的调整。

如果 XXX 为 JObject
//第二部分,定义接口的类成员(类方法和属性)的对象。
JXXXClass = interface(JObjectClass)
//第三部分,定义接口的普通成员的对象。
[JavaSignature('com/mediatek/telephony/XXX')]
JXXX = interface(JObject)
注意大小写。注意 XXX 前头加了个 J。这是 EMB 的惯例。

如果 IYYY 为 IJavaInstance
//第二部分,定义接口的类成员(类方法和属性)的对象。
JIYYYClass = interface(IJavaClass)
//第三部分,定义接口的普通成员的对象。
[JavaSignature('com/mediatek/telephony/IYYY')]
JIYYY = interface(IJavaInstance)
注意大小写。注意 IYYY 前头加了个 J。这是 EMB 的惯例。
IYYY 前头的 I 是 java 的惯例。

这样大体的结构就有了。

接下来我们为 类成员建立具体的内容(第二部分)。
第一步 我们要从 *.java 文件中找出 public static 的 成员。有 普通的变量常量,也有函数。
如果是变量常量,就需要在下面的 2.1 部分写出读写的方法。大部分是只读的。读写函数必须是 _getXXXX 和 _setXXXX ,大小写要注意。XXXX 是被读写的属性。
这些属性放在 2.3 部分。
如果是函数则应该在 2.2 部分定义。

然后查找下有没有个叫 getDefault 的 类方法,这个一般是建议使用的构造函数。
其他没有名称的构造函数,都要翻译成 init 。而且可以重载。一般就一个。
如果就一个还是私有的,那么就没有默认构造函数,就不能写 init。

然后找剩下的 public static 的 函数。这些要翻译到 2.2 部分。

这里要感谢 全知全能的 [成都]白马王子(286258698) ,他发现了新的经验。

如果是 非 static 的 public 的变量常量,需要在下面的 3.1 部分写出读写的方法。这些属性放在 3.3 部分。

JXXXClass = interface(JObjectClass)
['{782DB705-BAF3-4F7B-98B2-DA3D6E304292}']
{Property Methods}
//2.1 这里是内置的静态属性读写定义。
function _getXXXX: Integer; cdecl;
function _getYYYY: JString; cdecl;
{Methods}
//2.2 这里是构造函数和类方法。
function init: JXXX; cdecl;
{Properties}
//2.3 这里是静态属性。
property XXXX: Integer read _getXXXX;
property YYYY: JString read _getYYYY;
end;
也就是说 JXXXClass 是 XXX 对象的构造、属性还有类方法的定义处。

剩下的 public 但不是 static 的 函数 也就是 非静态的方法,要定义到第三部分。

[JavaSignature('com/mediatek/telephony/XXX')]
JXXX = interface(JObject)
['{D70F5051-D98A-46B4-AC6F-D5874EC7612C}']
//3.1 这里是内置的非静态的属性读写定义。
function _getDDDD: Integer; cdecl;
procedure _SetDDDD(Value: Integer); cdecl;
function _getEEEE: JString; cdecl;
{Methods}
//3.2 这里是非静态的方法。
function theYYYY: Integer; cdecl;
{Properties}
//3.3 这里是非静态的属性。
property DDDD: Integer read _getDDDD write _setDDDD;
property EEEE: JString read _getEEEE;
end;

注意所有的方法都是 cdecl 调用规则。如果遇到同名的请重载。

接下来说明下基本的类型变化。

Int 就是 Integer ,很多基本对象大家都可以自己想到。
string 是 JString 。
Uri 要翻译成 Jnet_Uri。

int [] 就是 TJavaArray<Integer> ,基本类型用 TJavaArray<>。
但是 string [] 是 TJavaObjectArray<JString>,对象类型的一般都用 TJavaObjectArray<>。

ArrayList<String> 要翻译成 JArrayList
而且任何 ArrayList<PendingIntent> 也就是 ArrayList<某对象> 都要翻译成 JArrayList。

有些类型的名称比较特别。例如 java 的 Phone 类型 EMB 已经翻译成了 JCommonDataKinds_Phone。这是因为 Phone 是 CommonDataKinds 的内部类。

如果发现不认识的类型,那么就应该是别的文件定义的。
这时候就需要把这个“别的文件”也翻译过来,这样才能顺利的完成翻译。

例如

Build.java 中 Build 类,你完成他的翻译后,就可以使用 JBuild(按规则来的名称) 了。 当然这个类 EMB 已经翻译过了。

虽然 *.java 是分属在不同的文件中的,但是我们可以把一组相关的类都定义在一个 Unit 中。 大家可以参考 EMB 的做法。

如果一个 java 文件内有多个类对象,例如 ContactsContract.java 那么就应该按如下的方法写。
JContactsContract_Contacts = interface;//android.provider.ContactsContract$Contacts
类内部的类要如下写法。
JStreamItems_StreamItemPhotos = interface;//android.provider.ContactsContract$StreamItems$StreamItemPhotos

[JavaSignature( 后面的部分和上面的一样。
大家可以产考 Androidapi.JNI.Provider 的写法。

【好消息】:java2op 或者 JarOrClass2pas 都能自动翻译接口了。大家不用人工做了。

接口的对象的使用。

一般如果你打算使用类方法和属性,可以不建立对象。
使用 TJXXX..JavaClass.YYYY 就可以了。
如果是 创建对象,有 getDefault 就一定要用。没有就 init 。

一般建立的方法如下:
XJ对象 := YJ对象.某函数(返回 XJ对象)
或者
XJ对象 := TJ对象类.javaclass.init 或其他构造函数。

特殊J服务对象,需要用 SharedActivityContext.getSystemService(TJContext.JavaClass.某服务); 的方式建立。
例如:
procedure TMainForm.Button1Click(Sender: TObject);
var
TM: JTelephonyManager;
var
TelephonyServiceNative: JObject;
begin
TelephonyServiceNative := SharedActivityContext.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE);
if Assigned(TelephonyServiceNative) then
TM := TJTelephonyManager.Wrap((TelephonyServiceNative as ILocalObject).GetObjectID);
try
Edit1.Text := JStringToString(TM.getLine1Number);
except
on E: Exception do
begin
ShowMessage('发生错误' + sLineBreak + E.Message);
end;
end;
end;

如果你使用一个叫 JXXXX 的接口,但是运行发生错误提示,没有找到他。一般是 [JavaSignature( 这个地方的路径错误,或者说,这个机器上就没有这个接口。

如果你使用一个方法,发生非法操作,说明没有这个方法(大概是名称或参数有错误)。

如果你使用一个方法死机了,说明这个方法定义到了错误的位置。

如何实现一个 回调(事件),请参考下面的代码。
TAlertDialogOnClickListener
TCopyButtonClickListener
TVKListener

如何继承一个 接口,请参考下面的代码。(当然这个,最好别分成两个类,下面的代码是特殊需求。其实一个类就行。最好是参考 如何实现一个 回调(事件))
TCommonAlertDialogRunner
TInputQueryDialogRunner

在使用 回调或者事件 或者 操作 JNI UI 的时候,有时候需要用 CallInUiThread 来执行
例如如下的代码。
procedure Toast(const Msg: string; duration: TToastLength);
var
ToastLength: Integer;
begin
if duration = ShortToast then
ToastLength := TJToast.JavaClass.LENGTH_SHORT
else
ToastLength := TJToast.JavaClass.LENGTH_LONG;
CallInUiThread(
procedure
begin
TJToast.JavaClass.makeText(SharedActivityContext, StrToJCharSequence(Msg),
ToastLength).show
end);
end;

最后请大家看看 Androidapi.inc 和 Androidapi.NativeWindowJni 的内容,大家就知道如何调用 *.so 文件了。

(C)(P) By Flying Wang 2013-10-05
辅助 By 爱吃猪头肉。

上面的版权声明还有代码中的相关声明请不要移除。

JNI 翻译 转 Delphi 的 经验 方法的更多相关文章

  1. delphi cxgrid 使用方法

    delphi cxgrid 使用方法1.绑定数据 方法 cxGrid1DBTableView1.DataController.DataSource:=DataSource12.去掉"Drag ...

  2. Delphi面向对象的方法

    方法是属于一个给定对象的过程和函数,方法反映的是对象的行为而不是数据,前一篇提到的对象的两个重要的方法:构造方法和析构方法. 为了使对象能执行各种功能,你能在对象中定制方法 创建一个方法用两个步骤,首 ...

  3. 【转】对于JNI方法名,数据类型和方法签名的一些认识

    [转]对于JNI方法名,数据类型和方法签名的一些认识   之前一直用jni,但是没有考虑Java重载函数,如何在jni-C++里命名,今天看到一篇文章,讲到了类型签名. 原文链接:http://www ...

  4. Delphi基本图像处理方法汇总

    这篇文章主要介绍了Delphi基本图像处理方法,实例汇总了Delphi操作图像实现浮雕.反色.模糊.翻转等常用效果的方法,非常具有实用价值,需要的朋友可以参考下   本文实例汇总了Delphi基本图像 ...

  5. Delphi中匿名方法动态绑定事件

    应恢弘之约,写了一个对其发布的匿名函数动态绑定到事件的封装,代码如下: type TAnonEvent=class public class function Wrap<T1,T2>(On ...

  6. Delphi GDI+ 安装方法

    [转]Delphi GDI+ 安装方法转自:万一博客(http://www.cnblogs.com/del/)GDI+ 是 Windows 的一个函数库, 来自 Windows\System32\GD ...

  7. [翻译] Virtual method interception 虚方法拦截

    原文地址:http://blog.barrkel.com/2010/09/virtual-method-interception.html 注:基于本人英文水平,以下翻译只是我自己的理解,如对读者造成 ...

  8. JNI系列——C文件中的方法调用Java中方法

    1.创建xxx.jni包并在该包下实现一些Java的方法,和要调用的本地方法 2.实现MainActivity中的按钮点击事件-即点击按钮调用本地的方法 3.在C文件中的方法中回调Java的方法 3. ...

  9. delphi中locate方法

    TDataSet控件以及它的继承控件,例如TSimpleDataSet/TClientDataSet等都可以使用Locate方法在结果数据集中查寻数据.程序首先必须使用SQL命令从后端数据库中取得数据 ...

随机推荐

  1. UVA 10791 Minimum Sum LCM(分解质因数)

    最大公倍数的最小和 题意: 给一个数字n,范围在[1,2^23-1],这个n是一系列数字的最小公倍数,这一系列数字的个数至少为2 那么找出一个序列,使他们的和最小. 分析: 一系列数字a1,a2,a3 ...

  2. 妙味课堂——HTML+CSS基础笔记

    妙味课堂的课程讲得非常的清楚,受益匪浅.先把HTML和CSS基础课程部分视频的学习笔记记录如下: padding #PS基础 ##前端需要的PS技能 - PS技能(前端需要):切图.修图.测量 - P ...

  3. python与正则表达式

    匹配一个字符: . 任意非\n字符 [...] \d \D digit \s \S space \w \W word 匹配前一个字符的多个: * 0->> + 1->> ? 0 ...

  4. window自动任务实现数据库定时备份

    原理:利用window定时任务定时cmd加载mytask.bat文件,bat运行php.exe程序编译运行mytask.php文件 ,从而实现了数据库的备份 mytask.bat 内容: D:\php ...

  5. Windows下的Memcache安装 linux下的Memcache安装

    linux下的Memcache安装: 1. 下载 memcache的linux版本,注意 memcached 用 libevent 来作事件驱动,所以要先安装有 libevent. 官方网址:http ...

  6. Jvascript简介

    一.Javascript就是我们所说的脚本语言.它不同于C++/java等语言,它更加灵活! 正因为其灵活性,没有那么多的规章制度,也是我们容易学的地方,但很多时候也是 令人无奈的地方! 二.我们要知 ...

  7. C++的简单“五子棋”游戏,只是核心代码,资源代码未添加

    ChessBoard.h #ifndef __CHESS_BOARD_H__ #define __CHESS_BOARD_H__ #include "DataStruct.h" # ...

  8. Sublime Text 使用笔记

    常用快捷键 command+shift+d   # 复制当前行到下一行 .

  9. nginx服务器配置

    nginx主要配置 #定义Nginx运行的用户和用户组user www www; #每个worker进程绑定到指定CPU ,均衡各CPU 负载worker_cpu_affinity 000000000 ...

  10. Javascript,颜色渐变效果的处理

    在搭建博主博客的时候,寻思着做一些效果,看到菜单,就想是不是可以做一下颜色的渐变,增加一点动态的感觉.有个jquery的插件,效果相当不错,不过博主还是打算自立更生写一下,看看能不能实现. 下面就是博 ...