Android : App客户端与后台服务的AIDL通信以及后台服务的JNI接口实现
一、APP客户端进程与后台服务进程的AIDL通信
AIDL(Android Interface definition language-“接口定义语言”) 是 Android 提供的一种进程间通信 (IPC:Inter-Process Communication) 机制,支持的数据类型:
1. Java 的原生类型;
2. String 和CharSequence;
3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型; 以上三种类型都不需要导入(import);
4. AIDL 自动生成的接口 需要导入(import);
5. 实现android.os.Parcelable 接口的类. 需要导入(import)。
Android studio工程建立如下:
app和remoteserver按常规应用建立,remoteservicecontract通过新建Android Library生成:
也可以将原本的应用模块改成库模块:
然后在remoteservicecontract建立aidl目录并新建AIDL文件:
建立如下三个AIDL接口:
aidl文件的声明和java实现如下:
(1)Entity.aidl 是声明本地实现的 android.os.Parcelable 接口的类
// Entity.aidl package com.example.remoteserver; parcelable Entity;
java实现:
package com.example.remoteserver; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; public class Entity implements Parcelable { private int age; private String name; private final String TAG = "Engity"; public Entity() { } public Entity(int age, String name) { Log.i(TAG,"new age="+age+",name="+name); this.age = age; this.name = name; } protected Entity(Parcel in) { age = in.readInt(); name = in.readString(); } public static final Creator<Entity> CREATOR = new Creator<Entity>() { @Override public Entity createFromParcel(Parcel in) { return new Entity(in); } @Override public Entity[] newArray(int size) { return new Entity[size]; } }; public int getAge() { Log.i(TAG,"get age="+age); return this.age; } public void setAge(int age) { Log.i(TAG,"set age="+age); this.age = age; } public String getName() { Log.i(TAG,"get name="+name); return this.name; } public void setName(String name) { Log.i(TAG,"set name="+name); this.name = name; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(age); dest.writeString(name); } @Override public String toString() { return String.format("age=%s, name=%s", getAge(), getName()); } }
(2)IRemoteService.aidl声明服务端供客户端调用的接口:
// IRemoteService.aidl package com.example.remoteserver; import com.example.remoteserver.Entity; import com.example.remoteserver.ITVCallback; // Declare any non-default types here with import statements interface IRemoteService { void doSomeThing(int anInt,String aString); void addEntity(in Entity entity); void setEntity(int index,in Entity entity); List<Entity> getEntity(); void asyncCallSomeone( String para, ITVCallback callback); }
java实现:
package com.example.remoteserver; import android.Manifest; import android.app.Service;import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.location.LocationManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.provider.Settings; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Toast; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; public class RemoteService extends Service { public static final String TAG = "RemoteService"; private List<Entity> data = new ArrayList<Entity>();
int mStartMode; // indicates how to behave if the service is killed final RemoteCallbackList<ITVCallback> remoteCallbackList = new RemoteCallbackList<>(); public void onCreate() { // Used to load the 'native-lib' library on application startup. System.loadLibrary("RemoteServiceJNI"); //加载native接口的c库 pthreadState = true; DataThread datathread = new DataThread(); datathread.start(); Nano_Printf("service onCreate"); Nano_Printf(String.format("<%s>",stringFromJNI())); //调用JNI接口 }
public int onStartCommand(Intent intent, int flags, int startId) { Nano_Printf("service onStartCommand"); return mStartMode; }
/*返回Binder对象实例*/ public IBinder onBind(Intent intent) { Nano_Printf("service on bind,intent = %s",intent.toString()); return binder; } public void onDestroy() { Nano_Printf("service onDestroy"); pthreadState = false; // 取消掉所有的回调 remoteCallbackList.kill(); } private void Nano_Printf(String...args) { String str = ""; for(int i = 0; i < args.length; i++){ str += args[i]; if( i != args.length - 1){ str += ", "; } } Log.d(TAG, str); }
/*生成的 Binder 对象实例,实现接口定义的方法*/ private final IRemoteService.Stub binder = new IRemoteService.Stub() { @Override public void doSomeThing(int anInt, String aString) throws RemoteException { Log.i(TAG, String.format("rcv:%s, %s", anInt, aString)); } @Override public void addEntity(Entity entity) throws RemoteException { Log.i(TAG, String.format("rcv:entity = %s", entity)); data.add(entity); } @Override public List<Entity> getEntity() throws RemoteException { Log.i(TAG, String.format("get:List<Entity> = %s", data)); return data; } public void setEntity(int index, Entity entity) throws RemoteException { Log.i(TAG, String.format("set:entity[%d] = %s", index, entity)); data.set(index, entity); } @Override
/*客户端调用asyncCallSomeone接口并传过来callback实例,服务端注册callback并回调修改结果*/ public void asyncCallSomeone(String para, ITVCallback callback) throws RemoteException { Log.i(TAG, String.format("asyncCallSomeone...")); remoteCallbackList.register(callback); final int len = remoteCallbackList.beginBroadcast(); for (int i = 0; i < len; i++) { remoteCallbackList.getBroadcastItem(i).onSuccess(para + "_callbck"); } remoteCallbackList.finishBroadcast(); } }; /*native interface*/ public native String stringFromJNI(); }
(3)ITVCallback.aidl声明客户端向服务端注册的回调接口:
// Callback.aidl package com.example.remoteserver; // Declare any non-default types here with import statements interface ITVCallback { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void onSuccess(String aString); }
app客户端Java实现:
package com.example.administrator.sheldon_aidl;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.nfc.Tag;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
/*导入资源库中AIDL定义的类*/
import com.example.remoteserver.Entity;
import com.example.remoteserver.ITVCallback;
import com.example.remoteserver.IRemoteService;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private boolean mBound = false;
private IRemoteService iRemoteService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mBound) {
alert("未连接到远程服务");
return;
}
try {
Entity entity = new Entity(100, "sheldon");
if (iRemoteService != null){
iRemoteService.addEntity(entity); //调用服务端的接口添加成员变量
iRemoteService.registerCallBack(mCallback);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
findViewById(R.id.modify).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mBound) {
alert("未连接到远程服务");
return;
}
if (iRemoteService != null) {
try {
List<Entity> entityList = iRemoteService.getEntity();
int pos = 1;
if(entityList.size()>pos){
entityList.get(pos).setAge(1314);
entityList.get(pos).setName("li");
iRemoteService.setEntity(pos,entityList.get(pos)); //调用服务端的接口修改成员变量
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
findViewById(R.id.callback).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mBound) {
alert("未连接到远程服务");
return;
}
if (iRemoteService != null) {
try {
final String para = "canshu";
iRemoteService.asyncCallSomeone(para, mCallback); //调用服务端的接口并传入回调
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
private void alert(String str) {
//解决在子线程中调用Toast的异常情况处理(还是有异常)
//Looper.prepare();
Toast.makeText(this, str, 0).show();
//Looper.loop();
}
@Override
protected void onStart() {
super.onStart();
if (!mBound) {
attemptToBindService(); // 尝试绑定服务
}
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mServiceConnection); // 解绑服务
mBound = false;
}
}
/**
* 尝试与服务端建立连接
*/
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.example.REMOTE.myserver"); //这里的action由..\remoteserver\src\main\AndroidManifest.xml中指定
intent.setPackage("com.example.remoteserver"); //这里即为服务端进程包名
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
/*实现 ServiceConnection 接口,在其中拿到IRemoteService AIDL类*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(getLocalClassName(), "service connected");
iRemoteService = IRemoteService.Stub.asInterface(service);
mBound = true;
if (iRemoteService != null) {
try {
iRemoteService.doSomeThing(0, "anything string");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(getLocalClassName(), "service disconnected");
mBound = false;
}
};
/*实现callback接口*/
private ITVCallback mCallback = new ITVCallback.Stub() {
@Override
public void onSuccess(String aString) throws RemoteException { //回调接口被服务端调用,获得结果并用Toast显示
Log.d("nano-client ", String.format("service arrived %s",aString));
alert(String.format("回调: %s", aString));
}
};
}
客户端和服务端的通信AIDL接口定义在remoteservicecontract库中,需要在各模块导入使用,
如果各模块在同一个Android Studio工程开发,可通过修改build.gradle直接应用:
也可以将生成的aar,提供给另一个工程导入使用:
二、后台服务的JNI接口实现:
目录结构如下:
![](https://images2018.cnblogs.com/blog/821933/201807/821933-20180705194628282-916274775.png)
1.声明native方法,如 RemoteService.java 中声明的:
/*native interface*/ public native String stringFromJNI();
2.通过javah生成native格式的头文件 com_example_remoteserver_RemoteService.h:
![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABSgAAADkCAYAAACbg8rgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAE4sSURBVHhe7d0HfBRl/vjx76bSSwgJSAdJkA52OoqKgiD2fqec7Yrg3f1+54kFC5Y77w4976eeov7v8Gfvnj+sgIBd6V2k2SAhNCmp+9/vszPJZJnZkmyySfi8eQ37zDMzz8w8MzvZ/e7zzPhOOXm4X1BtWe2OkMGDj7PGDvXVl5/I9m0/WmORnd58r5WKzf/tbW6laoff30r6nHa6tFj9jHyy1cpEuZSUJCuFw8HGzdukcdPafQ8CAAAAAFDf+caNG0eAEgAAAAAAAEBC+E6e+HMClAAAAAAAAAASgv6nAAAAAAAAABKGACUAAAAAAACAhPGdPIEu3gAAAAAAAAASgxaUAAAAAAAAABKGACUAAAAAAADQQJ0+oq8ZakNV10OAEgAAAAAAAGggGqWnytF9u0haWoqkpCRbuWLSmqfTdJ66JGEBSn9mf/nFr8fJiMyq3QLT7+8sZ/96uPT2cwtNAAAAAAAAQPU58gjJymguQwf1kNHH51q5YtKap9P69DzCyq0bfCdP+Fl5hM/vbyUjLxknQ9r4rJwgv3+LvPH3+bLKVzk/kfz+LnLOb7rImjq2XQAAAAAAAECiaCvJoYOO9GwlebCwWBYt/lqKikqsnPg5fUQ/+b8Pl1tj0avUgtLn2yUf/u/Tcu/fZ8usz3dJ/udvmvR9D31IEBAAAAAAAACo4/xlfklLTbHGRL7dttMMNp2m89QlvpPOrGhB6ZR14niZIAvl8Y93WTmBHew5Qm46vXMwvWOZPDF7qWxrO0CuuqiV7NzQSXr22Cqv/+8uGXJxK1n/RQsZcmyrYOvLBzdLr+uHSY7PJ/6vF8i9b202LSDPvb6LrHlwvqyQrsH0HJEJVvl5n79p1h2cL7isclt+JcFTAAAAAAAAHObOGNnPSgV9++NOWbb2W5Pun9tROrZrbdK2t+YHWztql+8uR7QxabX5+x2ycv331lhk1V0+6ntQ6j0jrzpul8x64N9yz4Oz5YlvOsuEIfZOdRJZP1vu/fuHstLECjtJT1lo5ntjQyc50wQSZ8vdDyyQ9T36yUjX+04G5uu52Sxz9/8uEzmmv/Tx+8Xn2ywv/f3pYH7Y5QEAAAAAAADEatXXP0j+zp9MeseufWY8Fjr/jl3B5bWcWJePOkCZ3bOztG3TXyZPuUz+eP2lMvnYVpLZuqU1dausWWclja3y8UfBpqN5O3eLbNhstXLcLfkFLQPLmUkhtsob/9kUTOZtkfUFLSSzbXA0eG/MS+SmKcMlx6frDeYDAAAAAAAACNIWke8sXCklpaVmvEN2K+mX29EMmlY6TeexW08qv98vX63cLNsL9sqXKzaZ8Vjo/F+u2Czb8veYcmJdPqaneGv3am3JaA/a1bqmabfyP14/TORtbUH5pny0g9aTAAAAAAAAgJvk5CQpLi4zaZ/PJ53atTaDplVRcamZJ1RJaZl8sXyTea0KXe7LlZurtHzUAcpt67dIvqN7tb9n/1rpap2d2UJkw3KZnx+oxLadpWeGNQEAAAAAAABAJf1yOkjjRqnmad12S0qlac1r0igtME9HK7f69L6X0Q5ekkQ0yOg2qIpxX/5Sef0LkSEXB7t4/7HnLpmfb2YK0Hk0OupcLnTcHpQ9TQevtCqTbR8tk/U9hgXXeVpL2VkQzHdfhoGBgYGBgYGBgYGBgYGBgYGB4fAdVqz/Trbv2CMLv1wvH3y8OpAXpGnN02kr1uuDc9yXj31w99b8ZZWGILfl/foU78s1BQAAAAAAAKCBOWNkf/NaESSML7v8aHhtg2/0eAKUAAAAAAAAABIjpofkAAAAAAAAAEA8EaAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAnjGz3+Mh6SAwAAAAAAACAhfL0HDSNACQAAAAAAACAhfMNGjq7VAOX+vbulsLDQGgMAAAAAAADQULTOzLJS0eMelAAAAAAAAAAShgAlAAAAAAAAgIQhQAkAAAAAAAAgYQhQAgAAAAAAAEgYApQAAAAAAAAAEoYAJQAAAAAAAICEIUAJAAAAAAAAIGFiDlDuvyTFDAAAAAAAAABQXTEHKJu2bGkG4IorrpCZM2eaoV27dlZukOa5sef3Em4a4qtbt27lx+PSSy+1cgEAAAAAAGpXzAHK5EbpZqhtU6ZMsVKJ17t3b5kxY4ZcfvnlVk78xbq/I0eOlOuvv94aqx3ff/+9TJ061Qw//vijyQsNMNoBMHuw50fibdy4sfx45OXlWbkAAAAAAAC1K+YAZUlpqRniSVtvafDqmGOOMS3xNB3aomvDhg1WKvHGjx8vTzzxhHTq1MnKiY3u3y9+8QsTULzllltkzJgxJs8p1v1NT0+X7t27W2N1ix0ECw1M6j6HDuHyw2nevLkcffTRcsMNN1g5QRkZGTJt2jQztGnTxsr1Fuv8Xuv97W9/W77t06dPt3K95x8+fLjcddddZt7c3FwrN6hJkyZy++23W2PhHXvssXLnnXeasvT9ZPNaLwAAAAAAQKLViQDls88+a141IJSVlWXSdp7tzTfftFKJl5mZKZs2bTKtKJ0mTZpkpcJ7//33Ze7cufLee+/Jxx9/LB988IG88sor1tSgWPf3nXfesVL1hzNw6QxgeuWHo4Ht0aNHS5cuXaycIA3+fvXVV/Lpp5+adCSxzu+13pUrV5pg4O9//3t55plnrFzv+UeMGGHOpzlz5sh5551n5QbpeMsob6swceJEsz59/5x11llWrvd6AQAAAAAAEi1sgHLb2SWSd15Z+bDrslQp84kZNO2cpvNWVUlJcNkWLVqUByjtvOTkZNOq7bjjjjPjdUFaWpqUhgRpNQA0aNAgayy8b7/91uyn3+83+2YHPFVd3N9Y2S0ena+hgxs732t6OOvXr5f777/fGquQk5MjX3zxhSxevNikI4l1fq/1LliwwBzffv36mXlsXvM//vjjcuDAARMc1RaTNj2nmjZtao1FVlRUJNu2bTPdtwsLC61c7/UCAAAAAAAkWtgAZXrzptIko1X5kBYY9yf5zKBp5zSdt7rKysokJaXyE8KHDBkiv/zlL+Xiiy+2coLat29vutHed999cu6555q8nj17mhZr9957rwns3HjjjSZf6QNBbr31VjNo2nbmmWea+e+++2759a9/beW6z3/KKae4BtH0/o+6Lg2wan6kAJveuzE7O9sM2jLuiCOOMEFL5ba/2hVcu/hqF13d1smTJ1tTRHr16mW69DrzlNv263ZdffXVpvuylnnRRReVb6tXPVRFaMtH56udDqXb4ZwvUh1GS7s2FxQUyK5du6RZs2ZWrrdY5/eyf/9+cy5rcFHP60g0qNi4cWM5+eSTTYtapdui3bQ1eBmt2bNnm3uj6vHUNAAAAAAAQF0XNkDZ6v8VStNH95QPTf5nl5SUFptB085pOm91aYszbQHmpC3R9H56oTS4pq3NbrvttvIWZ/qgFu0i26hRI8nPz5enn37a5Kuzzz5b3njjDXn99ddN2nbCCSeYAJAG8l588UUr133+d999t1IQzTZ//vxK+c5pbrZv3y6tWrUyrTDtoKzdItNtf7UruAYy9+3bZwJ3ffr0saYEu/S+9tprMm/ePCsnyG37tRv5kiVL5K233pItW7aYloKzZs0y07zqoSHw+XxmiFas83vRVrBaz9G65557pEePHvL555+b8WHDhplzOPQ9EY7eh3TRokWSlJRUZ+9JCgAAAAAA4BTzPSiLCg+aoSYcPHjQBCmjoV2qNRCjy/zrX/8yeXv37pUVK1aYtLZI3Lp1q0krba24bNkyM13TNg3KaSBIWxY67/PnNX882PuoQUndfg2ohrNq1SrzumbNGhOE1eCTTbuHa3fk0IfquG2/BiQHDhxonkKuLTU1uGnXl1c9VIUGUb1aQDpbStrc8nTcq4xY6DmhwWDdJ01HEuv84Wj3brtlbCR6/1Vt/avn9DXXXGPyTjvtNNOi1a4HfdVjF86oUaPMcddgtN5zEgAAAAAAoK6LOUBZWlxohniyu3Vrt1o7KOTs6q33ZVTOPO2GO3jwYHM/SGcgxg7eOYN4SltUHnXUUaZLtKZt2q1WA5za2vCyyy6zcr3nt7fFfnXS1pAaaOrfv7+V402Dk7t37zYBx9CyQvfXftV8e5od1NQy9F6Jdms5+9Vt+7UFZmpqqplHW59q8MwOlnrVQ1VEakHq5BactMUapNR7dypnQFnvvajdpLXLv/NekF5inV+5rVd17NjRtXu32/zXXXedOTZ6jPRWAUr3Xwf7VgX6agervej6jjzySNMSM/Q+qV7bCQAAAAAAkEjJnbt2m26lo/JT/1Lx+8uk6dKYY5tGcVHhIYGTc845Rzp37mzuw6f33dN7JmowRVuC6f0dp0yZYuY79dRTzYNENm/eLHl5eaYFoN6z78svvzSBPu2m/Lvf/c7Mq63PdD3ffPONGdeyL7zwQhO00ycc79y50+RfcsklcsYZZ8iJJ55oylm9erXJd5tfA3vaBVpp+Xp/QXt+1aFDB7NNuqy9Xi/6kBzdPw2k2vc8VG77a49rq9EBAwaYV33CtHZn14CWbqc+EEXL1ACVtrT02l/dZg1yaTdzDVDawUuveghHA2GhLTfHjh1rtiv0VYfQYKQ9rq86nw7KTutgT9flw9GAol1Pw4cPN/Wp+/fDDz/IhAkTTLDwueeeM/Wp9D6fdldqp1jn91qv0rrULvtOXvNrEFrvI6rH6+WXXzbns9JzTu8ZqvSYaytYvb+l1/bs2LHD3JNVW29qK0q7nHDbqdyOJQAAAAAAQKwaN4n9OTW+YSNHR9en2vLjpcH74bWbnWZeY7V/7+5KTxdG/XXFFVeYgKnSB+xoMMwZdFR2QNKZb+e5iTQd8aM/BNhBSw188lAdAAAAAABQXa0zs6xU9GIOUFYXAcqGyxlc9EqrcEFIApQAAAAAAAD1FwFKAAAAAAAAAAlTlQBl1W4kCQAAAAAAAABxQIASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAlDgBIAAAAAAABAwtTJAGVycrKccsop1tihdJrOAzQ0M2fOtFLR0fmrskyocOVEW36s22HzWndVywMAAAAAAPWLb9jI0X4rfYgUn8hFrdNlyf4SWX6w1MqtrH/jZBnQOEWe2VkoJZ4lVdi/d7cUFhZaY+7OOeccWbBggWzfvt3KqSwrK0uGDx8uL730kpVTf02ZMkUeeOABayyxevfuLZdccomsXbtW/vWvf1m5h6dEHRcNyk2dOtU1OKf5yjnNzlOxLuNVTiidL9x0mz2f23YoZxnRrDva9QIAAAAAgLqjdWaWlYpe2BaUl2Y2lWHtMuTqzm1MEDKU5l3VqY2ZR+eNh+7du0ujRo08g5NKpzVu3Fh69Ohh5UTWr18/mT59utx1111ywgknWLkiGRkZMm3aNDO0adPGyhVp3ry5HH300XLDDTdYOUHHHnus3HnnnaacY445xsp1d+mll5ogi87Xrl07k9Y8pw0bNlipxBs/frw88cQT0qlTJysnNj6fTyZNmiT33nuv3HHHHSbQXF8l4riEBuQ0bQ+hwuWFWyY03y1Pt8M5uOXZgxu7PLvs0PKVV75XmQAAAAAAoOEKG6BcerBUUps1lxatW8pVXTRIWdGtWtOap9N0Hp03HrRl5NKlS60xb0uWLJGhQ4daY5FpuX/7299Mq0sNxNnGjBkjX331lXz66acmbdOA4ujRo6VLly5WTtDEiRPlmWeekWeffVbOOussK9edzqM08KmtPpWdZ3vzzTetVOJlZmbKpk2bZMaMGVZOkAYdozFkyBA58sgj5c9//rM88sgjlQK+dVG4/apLx8WLBvhqIqBnBw/tAKJzPHRQzmAlAUYAAAAAABCrsAHKxXsPyv+s/04kJUWat2wmv+iUYbp066BpzdNpOo/OGw/dunWTzZs3W2PetmzZYlpbRmvHjh2ye/duWb58ufj9FX3Rc3Jy5IsvvpDFixebtG39+vVy//33W2MVioqKZNu2bbJx48aIXdVLSkrMa4sWLcoDlHae3kNTW28ed9xxZrwuSEtLk9LSyoFmDdQOGjTIGgvv+OOPlzfeeMPU9ffffy8fffSRNaXu8dqvRB0Xt8CeHfgLN02DhPZ0e9xOh7KXcU5z5jnzlT0eOo892JzBSvs1nNAyQscBAAAAAMDhJew9KG3HtGoqv+7VSaSkSH7au8/kNWveVCQlTR5as1W+2BXMi0ake1BqUPC///u/payszIy3b99eLrroIsnOzpbPP/9cXnzxRZOvgSTtSvxf//VfZjxa/fv3N2W9++67Zvy+++6Tm266yaTvvvtu+cMf/mDSNg2aOIMuGhTVVpQ//PCDaXWpgcpwdHm9n+a+fftk7Nix5WVpi86RI0eaVovO8t32t2fPnmadOu9zzz0np512mtl3pQHdyy67zKT//e9/l2/PmWeeaVqYaj1qsPChhx4y+W7z60OHxo0bZ/KUvT26faGtDMMFoHSbtBv9wYOHBqvd1uu1X9oydeDAgfLZZ5+Zenr11VdNXatYylETJkwwgVMNvq5cuVKeeuqpsPvldVzc1nv99debVqKvv/66nHfeeSaoPWvWLDOPzQ66has3+xwLPdeUW15VOMtxW1/oenRcea070vxu093KCjef2zKap9zKAgAAAAAAiRf3e1DaNAD599VbxO9LlhYtm5lB05oXS3AyGhrIa9q04n6WGqzTLti33XabNGnSxMoVk9Z5Y6EtGVu2bFkenLTpvRN1iIYGKBctWiRJSUlRt+DUFpva8tJJg5Z6H8tQbvv7448/ypw5c8y9OfPz8+Xpp582+erss882rRY1SKZpm95n8/HHH5dbb721PKir3ObX+rADPs7Az/z58yvlRwoKpaamlgeWQ7mt12u/tIt/q1atTMBPA4oacLTFUo766aefTBD60UcfNUFPFW6/vI6L23rfe+89cz7peaiBsz59+ph8mx1g08EOrLlxrl/pvPbgNq6ceV5DVemy9jaFlmkPXuxpzn3W19B9VM7p0bDLcZYNAAAAAADqv6gClKq0pFjKAoO2XNRB02Wlwe7K8aQt0zp37myNBbviakBQW+U5nyyt94bU+yVGSx+qo+VqAMoZAN27d68JhmmgSdORjBo1SpYtWyavvPKKuUdlNHTbnd3Kw3HbX92uFStWmPS3334rW7duNWmlLS11e3S6pm0anBw2bJhcffXVZt9sXvPHg3ah1+23OR+247Zer/3Sc0BpgPLrr782DyyyxVKO0uDhb3/7Wzn//POtnKpxW++qVavM65o1a0yQVIPW8WAH4eygXui4LTQ/dDyUBvWiCew5l3eW6Ryc7MChCp3mJXQZAo4AAAAAABy+ooqo9EsVuTKziSSXlUpxUXDQ9BVtGku/tOhaHkZL71s4YMAAa0ykoKBABg8ebLroOgOCOk8s9zjUe0BqcElbSo4YMcLKDQbB9Cnbej9CTTvpvQiVHZBS2kJQHwSjTxAPvV9jqJSU4JPPd+3aVR78tPOUBnqVM89rf+3gV2gQTFsMHnXUUdKrVy+TtmlAVgOc2urP7pqsvOa3t8V+ddJ91q7M2j0+HO1Cffrpp5uAogYqncfRa71e+6U6duxo1qn3tLTFWo52/dYnk2sLSpWbm2teldd+uR0Xt/Xa03V+exltxWmzA2/OYFws7KCdV/DOLts5n3M8lG5DrNvhLNM5OHmVae9/6HS3vGi2yy7PbXkAAAAAAFB/JXfu2m26lXbVN9UvV7ZtKs2aNZUyX5L8Y+N2+axgrxzdorGkJidJ7+Qy+f5gsWx379l7iOKiwrCBPQ1G9e7dW7Zv3y779++XvLw8E2Q6+eST5csvvzQt1dq2bStdu3Y1XXWjdfvtt5t7QOqgXae1laLSe0nqfQo1GKb3Lzxw4IDJ14DllClTTFrvS6hBRm2dp9t37rnnSr9+/UwrSt0eL+ecc45ptakP1dGgnd7HUIOe2hJP73Nol3/qqaea9erDgdz2V7tr/+53vzPzandnrb9vvvnGjGvZF154oQme6RPCd+7cafIvueQSOeOMM+TEE0805axevdrku82vXdW1K7jS8rWFqT2/6tChg9kmXdZer5sNGzaYAJ52gdYyNThq34/Sbb3h9kuPk46fdNJJ8vLLL5vzQcVajm67PrVd61eDlxqg/OSTT8qnhe6X13FxW+9f//pXM58djNVXfRK8dje3ado5Ho7usz2vHYSz71uq485y7Hy7fLfx0PntcfvVmRc6vwot0zl4ze/Ms/chdNud6dBlwk1TOh6aBwAAAAAA6o7GTSp6Lkcr7ENy+qb45co2jaV5i2Z6g0F5eEuBfPVT8AE3g5uly3WdM0SKi2Xvnp/kiR0HZEVJ5NaUkR6So7Q1mgZ63n77bSunMg1C6f3/wgU6UX9py0R9WNKNN97o+sCdhsoZ0NNXZ55bOhJ7XuVcVkUaV255tkjzR1O+inUdAAAAAACgbov7Q3IGNkqWpk0biT8pSR7evKM8OKk0rXk6TecZ3PjQrsFVpYFHr+Ck0mkEJxuuq666yrz+5je/Ma+HG6+gXGi+jnsNTtEGC6Oly4fjVr6OR1rOpvNFOy8AAAAAAKj/wragTPaJ/DyziXy1r1gW7y+2cisb1CRVjmmWKk/m7ZeSKJ4DE00LSgAAAAAAAAD1T1VaUIYNUNYEApQAAAAAAABAwxT3Lt4AAAAAAAAAUJMIUAIAAAAAAABIGAKUAAAAAAAAABKGACUAAAAAAACAhCFACQAAAAAAACBhCFACAAAAAAAASBgClAAAAAAAAAAShgAlAAAAAAAAgIQhQAkAAAAAAAAgYQhQAgAAAAAAAEgYApQAAAAAAAAAEoYAJQAAAAAAAICEIUAJAAAAAAAAIGEIUAIAAAAAAABIGAKUAAAAAAAAABKGACUAAAAAAACAhCFACQAAAAAAACBhCFACAAAAAAAASBgClAAAAAAAAAAShgAlAAAAAAAAgIQhQAkAAAAAAAAgYXzDRo72W+lasX/vbiksLLTGANQ1o0sK5e6DBdJcykT8vkBOrV4iAAAAANSEwEf7/YH/HktrERiaWZkAEH+tM7OsVPRoQQmgnAYnHzyQL839GpzUHIKTAAAAQIMQ+GjfxO+XKYV75IbAAAB1CQFKAOX+dHCH/rAKAAAAoMHyyxVFP1lpAKgb6OINoNyKvd9ZKZHH05rL7LRmku/jdwwAAAAgUWbOnGmlKps6daqVis6xpYXy5P58a0ykb/MOVgoA4osu3gCqx9F8chbBSQAAAKDB+Dw5PfC//YGfflMA6haiDwAqONpT7yU4CQAAADQw9gd+7jUPoG4hAgEAAAAAAAAgYQhQAgAAAAAAAEgYApQAAAAAAAAAEoYAJQAAAAAAAICEIUAJAAAAAAAAIGEIUAIAAAAAAABImHoboJwwYYI0adLEGqtZN9xwg5WKn3hv/8iRI+X666+3xqpuypQpVqqyeJXvxat8r+0JFUt9nnnmmTEf0yOPPFLOO+88ufnmm62cymq6frxEe7wibX848T7/q1L/kSSq/huamr6uxrv8eF4fYjknQ9cbqfxot9NLVd+/tf2+qM51prbUxPXncMd1o+6oznXscFMfrldoeA739x0ARFInApRXXHGFzJw5s3y4/PLLrSneNmzYIP369bPGatbXX39tpeIn3tufnp4u3bt3t8aqTrfLTWj5uu2333673HPPPXLddddZuVXntf1e2xMqlvpMTU2VLl26WGPRKy4ulszMTGussnjVf6yiPV7KbfvHjBkjycnJ1pi7eJ//Va3/cBJV/w1NvK9LoeJdfjyvD7Gc56HrjVR+tNsZTrjrj5dEvC+qsp21qSauP4e7aN5f1RHv8qN9P0az3pr4fFgd1bmOHY7q+vWqodLvDfZ3vjvvvFOGDx9uTUkcfa/H83uNF953ABBenQhQ/vvf/zavv/3tb+Wpp54yHxgiWbduneTm5lpjNeuNN96wUlUzadIkK1Uh3tv/zjvvWKnqefPNN61UZaHln3vuufLkk0/K3XfffUiAy21/I/Hafq/tCRVLfb788stWKnr6of/VV1+1xg4Vr/qPVbTHy2v7Fy1aJKeeeqr4fD4r51DVPf9DVaX+I0lU/bupyvlfV9T0dTXe5cfz+hDLeR663kjlR7udXiJdf7zU9vuiqttZk0LfjzVx/YkHrhveGsp1ozZU5zp2uKmL1ysv9fn64Oaxxx4zr7/73e/Md8Bx48aZ8XiLpd7Cfa+Jp8P9fQcAkdSJAGVJSYl5bdasmfz85z+XuXPnmnHbL3/5SytVQYOY2jokJSXFyok//QOVkZEhxx13nJUTu3bt2smgQYOssQq1sf2xiHVf09LSpHnz5rJ371754IMPrFzv/Y1VrNtT1+qzpsXj3FQHDhwwQcpTTjnFyqkQr3XUZ23btrVS0YnX+Z8oNf0+8io/1nqO5/UhlrK85vUqn/dQYiXq/ch1I77q+3WjNsTjOhYvsR6XeEnUemN1uF0f3Njf+0pLS80P5AcPHjTj4dR0vXl9r4kXPg8AQHR8w0aO9lvpWrF/724pLCy0xipoM3/b1KlTrVR4p512mnz//feyfPlyM37WWWfJwIED5bPPPjPdBfSX0U8//VR69uwpEydONN04nnvuObPcvffea5bp1q2bXHbZZSatv+Jt3LjRpNXxxx9v5tU/KPY2de3aVS699FLzgXX27NnmF1jVvn17ueiiiyQ7O1s+//xzefHFF839v0J/vXPuW+j2K73nka5X/1CuXLnStCjVe4i1adNGXn/9dXO/nPXr18usWbPM/L169ZJLLrlENm3aZLonaPlV2V+tL91eXca5jW7lq5NPPllOP/10s68vvfSS+bDhtb/aVUJbIYSmlVf5XtsT7ni51afeb2zo0KFSVlZmpj300EMmX8+3Z555xmzvN998I//85z9Nvtfxtelyzu3x2n637Qx3HL24nQ8q1uNlC91+m37w0/kffC3YmllNHnP2Iee/2/bY7139JXzy5MnSu3fvsPMrr/p3Y5cfStcRaX+dwr0v3I776NGjzfx6jrds2VJ++ukn8z6/7777XI9vuPe713nldX66ze+1/eHqP5ZybNG+j8KV43Y9tIWWH66eYzn/I72/3PZLafk6zT7Pw5Xj9b5TbuXHup3h6k05379Vua5Gur45hXvfxbKdyus4ep3/bvlef9+VW/nh3o+6fdFef7hucN0I3S8Vet1QbusNV89e2+km3PtRhW5PVa9jbryOi9v5HO64eHE73+z9ffDBB+Waa64xgeJw9ea13rVr13peN2y6Lmc9eL3v3HB9CF9OOPY6du/ebZZZtWqVGU9Uvbl9r1Hxqjev953X+8ttvXb5oZzlRWvF3u+slEjf5h2sFADEV+vMLCsVvTr1kJxbb73VSkVHu9/oly/b0qVLpVWrVuaDmH5g0T8Y6scff5Q5c+ZIo0aNJD8/X55++mmTr84++2zTJUY/xGnaST/E3HHHHdZYkHYB0C82+kFP/zjZ9I/LV199Jbfddlv5TdXnz59f/kdDX0P/gIRuv9I/uvoH99FHHzUfqtR7771n/iDv27fP/HHq06ePyVe6Da+99prMmzfPyqna/i5YsEDuuusua6yCW/nq/fffl0ceecT8kdZ9V177+/jjj5tXZXfrsHmV77U94Y6XW32ecMIJZv16boV+idYPRX/5y1/Ml3mb1/H14rX9btsZ7jh6cTsfVKzHKxK//9DfKdzOf7ft+fvf/27m1V/CP/nkk/IPw8pr+5Vb/buxz6XQQcWyv+HeF27H3S5Tz/UePXqY7rL6QVK5Hd9w73ev88rr/HSb32v7w9V/LOXYon0fhSvH7XpoCy0/XD3Hcv5Hen+57ZcKPc/DleP1vlNu5ce6neHqLVRVrquxXN/sczh0ULFsp/I6jl7nv1u+19935VZ+pL+/0V5/uG5w3YjmuqHc1lvVv4+h7HMjdLDF6zrmxuu4uJ3P4Y6LF7fzbdq0abJixQrTsk67xOq4za3evNYb7rrhxet954brQ/hyItGHOuXl5ZkfimyJqjctO/R7jYpXvXm977zeX17bCQANXZ0KUO7Zs0cefvhh88cnGto6pHPnzmLfP09/NVP6QUR/adKm+kqb6+sHHfXtt9/K1q1bTVrpL1bLli0z0zUdSVZWlvzmN78xv45p2qZdCbSrrH6Y+te//mXlhhe6/Uo/TOq9OM8//3wrR8p/VVyzZo35o5iUVHHY9Je4xYsXV7rpcjz31618NWTIEFPH+gGxb9++Vq477SZls3+RtHmV7yXc9rvVp35IGzZsmFx99dXmw7qT1qd+MHLWp9fx9eK1/W7bGe44enE7H8KJtT5VixYtZPDgwVF1aXHbHl2XrlfPA/212P41WoXbfrf6j1Us+xvufeF23O2grR4r7Zqjr7Zw56Ebr/PK6/x0m99r+8PVfyzl2KJ9H4UrJ9z1MLT8cPUcy/kf6f3ltl9uqvI+VfEoP5a/I1W5rrqdD1UR6987r+Podf675Xv9fVexXidVtNcfrhtcN6J5Xyu39Vb172N1VfU65sbruLidz+GOixe3803rRoMz2hJc60zHbW715rXecNcNL27b44XrQ/hyItH60NbJY8eOtXISV29e32vc5q9KvXnxen95bScANHRV/8QSR9p8XekHqO+++06OPfZYMx6J/sHSLxjavN+pY8eO0r9/f9mxY4eVEyzb+WrTX76OOuoo04pC05FomfrH6/e//7088cQTVq5IQUGBCfJolxPtiuCk3Sy0q41uk5Pb9uuvZFqurkNptz27fvSPsg5Kf7VT2gokJyen/Emt9mtV9tcu216f8ipfWxToPukv084PjsptfzXviCOOKA8+2/vsVb5y255w2+9Wn40bNzZ/8PXXVbsLiF13bvXpdXyVvR16jG1e2++2neGOoxe388HmVj/h6tNt+7V+tCvQu+++a+WE57U9H3/8sVx55ZWmtYKT2/zh6j9W4fbXjdf7wu2429sW+qrLhjsP3c5/r/PK7fxUXvN7bb9X/cdajor2faS8ygl3PQwtP1w9x3L+R3p/ef29CBWpnND12rzKD50/XPnh6s1ezvn+jfW6Gu76FotYt9PrOHqdV175yu3ve7jzJPT9WJXrj9d57lafdpmhr7os140gr3Lq83VDea03lr+P8RJpv0LrIRyv4+J2Ptvlhr66nTM2t/NNA4l6r76//e1vpuutM0DjVm+R1ut23VBu1yuv89+L1/nsVk647WzI14dQzvefrufoo482f8tUourN63tNvOpN2dvtfN95vb+81gsADV1y567dplvpWlFcVGiavjvp/WX0FyftenHSSSfJ9u3bK13Y9SE5el8ON9r6S+/Tob8SK/0VTsvXcvRpnVqWdnfQX6CUrkOn290Jtm3bJhdeeKH54/bss8/Kzp07Tb5NfzXXpxy//fbbZlzn1/v56H1K9N4uW7ZsMfn6AVY/NOkHqS+//LLSr3sdOnQw03RZZzcGFbr9Ou/48ePNw0v0j55+8LJ/JdZf2QYMGGBex4wZY7oX6B9R3X69r6d+gNM/xvrHNdb91fuiTJkyxaR1f3X9mzdvdi1ft1V/GdS61j+qr7zySsT97dSpk5xxxhmmzjStH/q1HK/yvbYn0vEKrU/99V3Xe+KJJ5rjsnr1arn//vvNNLf69Dq+ekyuvfZak9YHyuiHC+365bX9btv517/+1Szvtl4vbueDdhuJ9Xh5bf+oUaNMtxadT/2yaK95Vf+T3uKQ899re3R/td5D98Vtfu22omKpBy9e++sm0nUg9LjrfmtXH90+56Dr+OijjzzPQ7fz3+u8cjs/ldv8kbbfrf5jLccWzfsoXDnhrofKWX64etYWBdGe//a4Lut1XoXul815nod7n3q972yh5ce6nV715vX+jfW66nUexirW7fS6bnid/175bn/flVf59jTn+zHc9d8N1w2uG9FcN5TXeehVz+HO26qI13UslNdx0f0KPZ/DHRc93m6f5d3Otz/96U+m9Z8Ge/ThmXr/Prv+3OpNj5HXejXf7bqhZbhdr9y2R7l9F+H6ELkct3qzv/d16dLFdInWY63bretyK7826s3re02s+6vzu9Wb1/su3PsrdL3OlqZOoeuKRujnfQCoCY2bNLVS0aszD8mpKn24h3ZjmDFjhvlwoV8+brzxRvMBtTr0y57+QdBf1PSPwz333GNNiS/n9qP6qM/qcd40e0CrzjV+/qNuqun3UaLep6Hrjfd1nutPzYnn33fUDK4biVHXtqcu4bqBhkTvJ+vGeY/NaPGQHAC1oSoPyan3AUon+0mm2k38z3/+s5VbNfoERP3Qp79svfDCC+X3sQHiLZ4fOKrL+YHl/x75X85/NGhc5+uPeP59B6qjrl03uI5547qBhoQAJYD65rAPUAKoHj6wAAAAAHULAUoA9U1VApSR72QMAAAAAAAAADWEFpQAyvGLKgAAANBw8XkfQG2gBSUAAAAAAACAeoUAJQAAAAAAAICEIUAJoDKf9QoAAACg4eHzPoA6iAAlgMqsu9J28JcGEwAAAADqvXTr1f68DwB1CQ/JAVBu2d7vHL9a6E+rfHoBAAAAGobKn+95SA6AmsJDcgBUy8tpTa2UIjgJAAAANBwVn++/TG5kpQCgbiBACaDc9PRW8n8pTawxxQ1qAAAAgIbDJ0uS0+VnTdpY4wBQN9DFGwAAAAAAAEBc0MUbAAAAAAAAQL1CgBIAAAAAAABAwhCgBAAAAAAAAJAwBCgBAAAAAAAAJAwBSgAAAAAAAAAJQ4ASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAlDgBIAAAAAAABAwhCgBAAAAAAAAJAwBCgBAAAAAAAAJAwBSgAAAAAAAAAJQ4ASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAlDgBIAAAAAAABAwhCgBAAAAAAAAJAwBCgBAAAAAAAAJAwBSgAAAAAAAAAJQ4ASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAlDgBIAAAAAAABAwhCgBAAAAAAAAJAwBCgBAAAAAAAAJAwBSgAAAAAAAAAJQ4ASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAlDgBIAAAAAAABAwhCgBAAAAAAAAJAwBCgBAAAAAAAAJAwBSgAAAAAAAAAJQ4ASAAAAAAAAQMIQoAQAAAAAAACQMAQoAQAAAAAAACQMAUoAAAAAAAAACUOAEgAAAAAAAEDCEKAEAAAAAAAAkDAEKAEAAAAAAAAkDAFKAAAAAAAAAAnjGzZytN9K14r9e3dLYWGhNQbgcDO6pFDuPlggzaVMxO8L5NTqJejwEaja/YH/HktrERiaWZkAAAAAANSs1plZVip6tKAEUGs0OPnggXxp7tfgpOYQnKwxgapt4vfLlMI9ckNgAAAAAACgriJACaDW/OngDm3Yh1rllyuKfrLSAAAAAADUPXTxBlBrVuz9zkqJPJ7WXGanNZN8H7+T1IRjSwvlyf351phI3+YdrBQAAAAAADWHLt4A6jZH88lZBCdr1OfJ6YH/7Qqn3SoAAAAAoO7yjRs3jpvAAagVby5fZKVExvcbaqVQU6hvAAAAAEB94DvvvPMIUAKoFc9/+q6VEhnZtb+VQnVlZ2dbqcqc9X3+8adYKQAAAAAA6pZavwclgMPXgo2LrZRI/9ZdrRSqq2Wr1laqMmd9D+82yEoBAAAAAFC3cAM4AAAAAAAAAAlDgBIAAAAAAABAwhCgBAAAAAAAAOKgUaNGcmSP7nL8MUfL6JHD5dSTR8voEcPl2KMHS9cunSUtNdWaE04R70GZ1TZTunXtIo0bNZYDBw/Ixk2bZXtevjUVAKJX1XtQnjnuDCsVvTf+85aVaviqcg/KtpP3mNe8WS3M6+jRo6VZk6ZSWFwk77zzTqDOx0uTpk3lueefM9MBAAAAAN58Pp9079ZVunftIt9s3CQ7du6U/fv2S3FJiaSmpkizwPertpmZ0uGI9rJ67Tr54cdt1pJQYVtQZrVtK+NOHyt33nGH3HlnYAi86vjxxx5tgpZNmzax5gTiw9dzsKRM/Yek/OFJ86rjTh26dJezL50sF1z5S/Oa1a6DNQVAVaWmpgWu91nyxn/elNZWsPP9eXPNKwAAAAAgstyeR0p6Wpp8uPAj2bBxk+zatVuKiovF7/dLUVGxFOzcJWvXfy2Lly6Xfn16S6cOR1hLQoUNUHbr2lkuvvhimTx5cvnr5ZdfLtdcfbWcNGqkHDNokBx/zGDJObKHacIKVFfyuMki6VbgO/Bqxh2OHz5aUtPSTVpfh40Za9J1UVnWSLlu2lVyUlbDfFB+mb+PXDDtHOkXuNiigj93iry25BWZmlu1evH7x8kDS/4m4xNcr/v37bNS8eF8P4Q7d4LTGu77BgAAAEDDk5HRWpo3ayZr1q2XwqIiK9fdzl275OPPPpdeubnSrFlTKxdhu3iPGj7MtJwM9cMPP8hDDz0kBw4csHKUz0SC9+zda43rF80sGXPtZBne1mflBPn9a+WVu16U5T6fZI+6Sq4d1taaEpi29jW544WVJq1fVC+6eYL0Csxn277wcXl43nZrLChcGTXh9ltvtlKR3XbHXVaqMmfd+P15svCxf8oH2yvXky0470SRV7znqUn2trZddLc8t6Jm168tJ0OVPPJfIruDtxXQlpOhnnvif6xUBec54XbOOPU7748yLG9WpXnK+p4j04fmy6OPzJNtjvOvLnDumz9vUbW2sTrHNvj+7CWrrPdyNKrTxfuBmTOtscimTJ1aqYu3358rN7z2rFx5yCrnyU0DpsqbdegYa4DywaVj5N0YtiueXbx/2r9P5s4Ntp684PwLDuni7XZdXvPqjJjOn3DnTnDaEMkLc00EAAAAgLpk0IB+8v0P22Tbdu/YQ6jOHTtIy5YtZfnKVVZOhXh874okXDwgEXGosC0o9Z6TGoTU1pP2cPDgQXn44Ydlz549UlxcXD6UlZVKj+7drCWDknzb5YNH75Hb77pbHlmYZwJFmr5jxkvmS6kGhq7JXSeP3DnD5OvwikyQW8/rY5Wg1snL1vTb7nxc1uZOrjQ9ujLqngHnT5bctbPM9t4x4zG+iNsK91sJi45bwUlVXFRopYJCx5UGF+1z4rY7X5OCoRPDtsZaunqdtM09SrIdrbkGHJUjaxfVveBk6Pk+/RWRUaOzrakNX2lpacTBjc+3VmaeNUj6Dxwk5z+5STY+eaFJ9x94Q50KTiaSBiW1i7cdnFTe95/MlwX/tK7L/1wkGRPPpSUtAAAAgMNWq5YtTcvIWGzLy5M2GRnWmJuK71061HSDsURL7ty123QrfQgNPGo3v1tuuUUuvPBCOeOMM2T27NnSqdl+aZrukyZpydKhTbqM7NtaLhiaJZ9vLJIt335nLV1Zs65Hy1GyVr7YFOw2qN39zj31gLzz17fkG0eA4MeVO6X9pCGSvfZL+WZflvQbkSl5H66S7YF5fL59suGLdZIy/CI5rnCBLJdREcvYuC/+B3De/A+jHtyYfR+8VV5+caXsc2y35v9y6qnSImS7/dJUuh/TS2TNofsTXOZiGTdyhIwaMVzaFXwoK61gp2kFePUkkz8yO0vaTRpWXicajb/w5l/IudZyvZPWymcbu1bKG5ldIHNX+kxEXVt6ZvYaYfLmr8oz5dcE//ffSFLOYJGUVBOcLH3575UClHt275b2HTtJcnKKCU4ufG+O7PupotWuatd7mHTZsVDmbd4fOGfyJKndadL1QPB8ca3fbUnSfuxAaeqom5Mm+WTVi8HzrlI9HpUka77YJHuztaxjpEe7s+ScSdmyY36+9L12ilx+esVxWL6tb6A+R0iSdf56HavgsQjMt7O3XGetR4+H/V6xub1nfPs2y0rHeyqW8j/b2PSQYzs3v3el/SoIbPuPZl8PLdcvld+f0bhy149WSuThxq2sVGS5OT3l008+Eb13xwsvvigvPP+8NeVQSUlJcsIJJ8i69eutnMoyT7hQTpH35NlPd1g5gXNg3N9k+Qv3ynXXXivXjW0kc5/5RPJ6TZXX379QTux1r/zp3l6yZW6u3B8Yb5d+rfzz0RsD8/aSrQ+nyK+WPi9/0uV6fSsPz1lvtYD8paQ8PCdwxRsfTG8dKy9a5Y9Nn2fWHZzPWtaxvEiOnH5dd/nmkTmyLsp6bdSosZWqzFnfT7Zub6WCmg4OBvf3Lw7eMkEfijNo0CBZuXKlaU3Zr09f6dqtq2zYsMFMtwWPeyfZ/1Xw/eLvdoyMS1ojLwSuC8Fz8BgptM95+9zT80gq3g/bQs4d53tsVDuf7GjTuLx8AAAAAKjr9P6T69Z/bY1FRxvY5OYcKRu+2WjlVAj93qW0VePJ114vY5uvq4itBb5L3TYpKxin6HfuobEL+3tYFPEAZ6ynJuJQkYRtQalP63773ffk1ltvNcOMGTNkQEaejO3XSC4ZliFXj2krFw/NkIGd0yXJXyz79oW0fgsnK1ParltzSPe+JN9KWbUuMC3LygihrTJXrs2XjMzsKpdRXdrF222Imm53gUifa2+S226+SW69ZqRpvZe0fb48HENrSj0pfnVVjqx9LBhND7Zkujp4jzedNjGjPNo+fXXgDWMv5w82FZbXgsvpoN2btd6emxFs8aotD9fmDJEx2dvkvUdmyYI8v2lOXJNd55V/yxopmfkr6fTi3XKVf6M02/WDNSUo/8fvpFXzJrLqq0/l5dmzZHtgPNQP+QXlLSL1Ddw2Q8z54lW/9vmS29tqidivl+Ra55Wpx6H55S0WH12bI2eXt1jMEVkdbBG8rP8IGVbwenl9HtI8OsyxCsqRSUetKZ8mQ4cf0iKtfe8c1/NdVaX8AeJ1bCv2a2n2qAjl1r7zzj3XBCnjRe8Z+fpVm+T8AQODLSznjpL7pgYuxMYokXc1/wZ5U7TeR8loudHMd9O8UXK36Yo9UPoNuFnmjvqFx30nA/Od8p5Zpt8FT4lcca25v6TP9x+ZYlpxBvLDLl877IfiuD0w51CZMvzqaeb6NT1wnVk4f4WVH7tw1yoAAAAAqA+KiookLS3NGotOamqqaRjoreJ7163TrgrGZxZV7gFq9/78Qb+7h4ldRB8PCC9c7KG63+3CBijVtu158snnX8rcDxfKSV12S05msfhLDsh1/1hS6VWHSf3du1e6aZ8ZrhlreFltM81rdcpIJLPdOTkirwQP6CsFQxwnTgxMgPaj8oCbBuAW2oHZkGmyfI2sDaaCAbj8j2TecmvcQQN6J13zR7n9lonSy9e2xoK8kWzcsF6+/26rDB0xysoJ6j/oaCkqPCjLl3xp5RwqacVLpk6vvWWaTL95orQtqGiB6cXZzdu8wVcHAy4aFMxqO9SUpRcFvfdj27b2/U7XySq7DrfnS17OhPJg8yHCHStjnbzyvBXk2bZa1uZnSNtYTom4lu/Yr4jlJkY8g5RHjR0l3br+XJ5fukSWLVksz1/RVbp1O9KaOk/efdNKGvPksZlrTOrrjZsCo+9ZXcS/lo2bAsvZi1UyT26aYhWyZo7MDcx3pBX/1HtjTn11sSxfepeMFq/la0dsD8Wp6Gow/bF1kntVNYLW4a5VAAAAAFAP7Nq9W1q3ir6XoMpskxFYLvhsAHcV37vKbw2o35cyc6RP4Pu8BgSH5QS/v0eKXVQr3uAULkZQze92EQOUTi0blYm/+IAZ/nFl50qvOrRIj/4L6g+r1kleTq9DWolp677eOfmS53Ff0WCLuHxZu2pblcuoLn3wjdsQLW3hJ46DZoJj5SdOfFQleGua4t6sN0G929zvUyPpifTBO3OkQ+fucvalk83DcfS1/+DjZe47/2fN4W35C8GWoNPvek3yAlWh50tY5W/yvoFzxxGgC9CHLmlZ9uD2y4K+KR+ecY9MX5RpLggX9I1/3ZnzJiPTPQB6mNHgpAYp42bezaYlY/kw9T/WhJpjupUvvVfkD9oC80J5YpM1IcGKi4tke+DiqV2+9TUi8weu6kHr+vpDEwAAAADYNm/5Vjp36mBuORatTh07yMZNm62x6GgP0HmLxPQA1aCkLFpQ3ssymthFTarud7uYApRTZ62W/IJd4i/ef8jww/YCMz1awShrjky6dlR5wCX4lKAJkuuMuDoEp0+WYQXB6VUpIx7cuneHDmGZ1nYVgVVtsZeXV4X7OppyhpS3XApGz4OB2WDwtmJa+9FDKprWmmDcEBnVLziqAd2TRmUFTya73rKPktxgQ9WE2btnt+zcs0dS04L3yNPXfQeL5LtvvzXjUek3XIbJOlkZIT5Z3s17UqCeHN2oQ+uxrO9I15ZiZX37mOOprTf1gVDmFgROYY5V1JYvkIUyRK45v6+VESzngsCxi0v5bmqq3GoIDU6ae1JaQ1WsnjNPNjq6V/vHTamVrtZHHdlVZN7jMnNt4FzrNVZGR/9Q8ypLa19int5tP8FbabrN5XskJaO0/KE4bg/M8WSuFdY5sS1fCqTi17hK1x0PYa9VAAAAAFAPFOzcKXv3/iS9cnpKehRdvVs0by7JyckxP1hH6XcoyR0uowJfnOzGWNHGLqqtqnGoKMQUoFRPvrtZ/l9en/Ju3Tro+Oy5W605oqet3F6xuuJqE9Tbb/mFebJ15ShvjpwdZnp0ZdQtGlj9x2tSvl+T5HVzD0g9sNdNu8rjJKq494AO2pW4/bZ5gXIKKu4FZ+4DEHwEvK7j5UVSPu1sWSdrpUDyAueuBuOeeewjyZgYLGv6zb0kb+42+WHuR7I2Z0Iwb1Km2D2j7ft+9jprWq0/Hd0OTtr8gX9NmjW3xtxpwPWCaX8M7oc2CH0k+DTu8PUbbMma1bZtefduFVqP04/Kdw98LxfpHZiu81wztEAWBurTKXjM3Y9VtOyn4utT6rUMU84kkXmBdVW1/EjHNh7bHW+hLSd13B6qwrf2AfnDkyJXPhfs4r38lK+DQcMatnrm4zJ31F3Bdd7XVTbVQgvKoh9SZO+CQx+os++TxlJSkGyNRaPienT71UOl4DXrumP9mmdPC153wgt9j13TtoAu3gAAAADqnbXrv5bCoiIZMWyIdO/WVVq1ailpqalmWkpKinTv2kWO7NFd0tPTpKSkxOT5XJ4xUaFyHOg6bZyktBeb5Eiu1XhPRR27cIgc64lfHCoavmEjR8cUUk0eeLqkDBhrjVUoWTpHSpdE7nqLxMgedZVck7tOHrWCdfWFdut2Bin1yd36cBzUTws2LrZSIv1bR99k8MxxZ8gDM2daY5FNmTpV3vjPW9ZYw9fS42E2zvoe3m2QlRJpdsJBadynyKT3LU6X/V9V/iEAAAAAAFA1jRo1kk4djpCM1q2lSdMmJkhZVlYmm7ZslbLSUunRvZtJp6akyO49e+Tb7763lmxYYo1DxRygTP/ZA1bqUIX/b4qVQjgaSXaj9wiIF21FqE/q7mWdBH7/WnnlrhddnwBdl2W16yDDxow1QUoNTi58b47rk7udaqN+UTXVCVDGigCld4BSNR95wLzunX9oi0oAAAAAQM1o3LiRtMvKkjZtMsyTv/U+lD/8GGUzwzqsunGomAOUAFBVVQ1QIryqBCgBAAAAAKgrYr4HJQAAAID6wyd+yW0icm62yF09ffLSwCR5/9hkmXlUkjRJpq0CAABIPAKUAAAAQAOS6hPp18wvF7Xzy309/fL6QJ883Fvkl51EhrT0S+uUMvH5S6V/0zI5P7t+3f4HAAA0TAQoAQAAgHosI1VkWMsyuaZDmTyUWyr/GVAiD+SUyVVHlMmxzcukaVKpSJn7MDajxCoFAAAgcXynnnoq/ToA1Iq313xmpURO63WclUJNob4BoOFJ9/mlR6My6dW4THoGBn3NTI3i43xZyDxJFS0nr1ruk1X7aEmJhimjZSMrBQCoy3hIDoBaw0Nbahf1DQANR/u0Mrm+Q7Ec08zvjC0eqrhU/AdKRIoCr4FBSspEysrE16R54JO/taA/8PG/7IBI83TxNU2TpNEXSsqk64PTgAak/9FDpWXgPAcA1H108QYAAADquP8+olCOa1oiSf5Du2lLcYn4C/ZJ2dZd4ve3lqTjJ0jKz26StBmzJX3WB9Lo5eWS/uxnkv7Mp8EhkE6d9pjI7gNm+bIv3w0sR5sFAACQOAQoAQAAgDquT+MS8ZeVVR5KSqUsf5+U7U6SpNMnS/qDb0j6I3Mk9brbJPm08yUpd4D42mSLpKRYpVRIGnCCSPcBUra3UPwFP4p/0wprCgAAQO0jQAkAAADUcbuKtat2RatJ/75CKdu6R5JPvVwaPTlXUi+5Xnydelhze/D7xf/T7uCwb6+kXjpFZI/VivKLd62ZGq712/bLXW9ukjF/WSK9pn1qhlP+stTk6bTqKCopk9tf3ySDbv9cBgYGTWseAACIDvegBFBruCdi7aK+AaDh+EP2XhnTsig4UlwmZXmFkn7bo5J87OhgnoP/wD4p/fhdKVv1lfi//UbKvt0g/l07REqKKz0cx5eWLNIsVXxNUkVaZ0v6vW+Lz75PZYzOe3iFWfb5a/tYOXWHBgpn/GezzP5km7n9pspoGmxVWrAv+BRz3e0Lj82SW87sKo1SY2/Dcccbm+SpRT9aY0HXjDxC/nB6Z2usbikrK5O1G7fJ93m7xR/416FtK8ntli1JSVVvv/LAe9/KwE7NZGRuKysn6MN1u2Txlp9kypiOVk7t4R6UAFB/VDtAWebvIxfd3EtW3fWiLK/iB5r6oCxrpPzqqhxZ+9g/5YPtVdvPulBX8dgPoKpMwExPu8BVh4BZzaO+AaDhOK3FAfl99k8m7S84KKlX3CYp4y81406lyz6RotuvCcy0XyQ9WSQlSXwacNPAZISPfmk3zpakHgOssdh0v/ET8/rNvSeY17pCg5OTn1oji77eI62bpMivTuog4/u3kawWaWb69j1F8uayHfKPD76TnftL5MQeLeTJK3pJWqDeYqEtJ3cfKLXGglo2TpbFtx1rjUU2b+1O+cOL30je3mIrJzptm6fKved0l9G9Wls5ka3+5gfZ/H2BNRbUrWOm5HbNtsZio8FJHVoE9vm2M7vKmN7BbXlv1U65/Y1NsidQNxqgjDZIef4jK+WLTXutsaBjujY3AfBw00IRoASA+iPqAGUwuDZBelmBNf/a1+SOF1bWetCt33l/lLNzD12PvT01pTYClKF1vObVGfLcivjWKQFKJJKzRd95nfrIjynBLweIvzS/X97ftMQaI0AJAPVdVkqpzO6SJ1Lql7LC5tL06Y9FkpKtqRWKHr9Hil/5p0hq4HOefqYsC3zUtwZtPWg+/WmwMjVJfOnJ4mscKMNqVZly6s8k9YI/mLSXWINosQTPvttVKH8MlP3Vlr0yuHNzuefc7tKhVfWCS7e+utG0nOzboak89rNcybYCk6G27SmSXzy1RlZ+v18uOzFbbp/YzZoSHTtAGyqWgO3xM76MOThp03r+dNrR1lhk73+yRopLKgdUU1OS5eQTellj0bODk9GINkgZrj512nPX9pZju7YweZ9v2iMXPLLKta6jDVB6f9fNkjHXTpbhbYP5yp+3SB59ZJ5sC8xrT2+76O5K39siLVcdwW0dInkh3+fM97xJIi8H1pF1/k2e35mnP58X07YFvz8OkSxrWk18R/XCd9eqKfN3ltEXnyid7fN560cye8EWkwbqsqgClGV9z5Hbz8qtdDHSvF9lLpB/zG1bqwFKW20HRuMh3DbbfxTlteAft+AfteGS90j92T8gkvmblkhS+VNC9byOePlBlVWuXwKUAFD/PdVxm7QvLpSkvqdIo1setnIPVbpmSeAL6dfiLyoUX7OWgaGF+Jq3EmncNDCxxNyDsmzrBild/pmULpwjkhIos2Wa+DLaSfr9c8N2865KEC3a4Nllj6+SjfkHTTfhJVt/kk4ZjeSZq3tbU2O3btt+OWPmMtNy8o3r+0u7wD5Oe/kbM23G2d3Nq3P8x91FcuaDy0xLyrem9pec7CZmWjTiEaAMbYWq45HSKnS5aMQrQBlLcNIWTZDS3qdQuo+h+6/c8lQ0Acrw33XlkACkNpiZJK9XCmB6BShD821paWlyxtjT5K05b0tRkXXrhihFE6C0A41u3z8jbZvTId9RA/UyfaLIK47yqrMvKjSY6/evLS+fAGXsyroMlZ8N7SRbFj0j8zdbxzyQN7HlCnlj2W4zXhVl/pYyePxYabni2fJyYxWPMuqTw6HOBvbvJ71ycyU5OUlKS8tkzdq1smTZcmtq7CL2XTAXpYk5h/xSkrTiJXl43nZrDNWWnSkZ+R/JPOtYJvm2ywePvkRwEg3Kf5plWClFcLJmVdTv0kbNrRQAoD5bvD818OW9TPzFB60cd8m9BkrKKedK6rhLJGXkeEk+eoQk5fSXpE49JKlr4ItE3+Mk9fSLpNF//02azP4oMO0EKd15QMryv5OyDRWt793YwUntTqsBIXuwOfO0lZuKNqCp9ynUrroPXZJjXr/aXLkbb6ye+2x74LuMyK9P6miCk+qNpTvMYHOO6zw6ry6jyzZkR2S1tFIVOmZXvndkND75Zo+Vit7HG6oeJIm3qnzXXbp6nZWqGv0B4Mxxp0u3rl1kwvgzwv4gUDesk1V2vGH5GlkrGdLWuhNAdffFBCBvDgZLb78rOEy/a430vnaUZPv9krR9vjw84zETnNRA5knX/FEu6Jv47xDx3hYN8p414UzzWh2m5eSQjpWCkypp86JqBScBL72P6iUvvfqaPP3s8+ZVg5XVEfnmKv16Sa4jcBaJXuQvmPZHue3mm8xw67RzpF95iymR7FFXuU4LXe66UVkmP1Ze5VRcRILTb71mpGSV9Q6kr5KT+o6U66xl9CKjvwwdsnzg4nmdtb3BdQSWG3XofCo4b8U2RHXh2pYvBZlDZFQ/azxEuPrxqlO3fOd+qHDHK9J+ArH6U2Zneb+pM0hJAL5m+WR5o2by6/ZHWuMAgPps8cF08aWKlH71kfj3xufLpq9Fa2l0+yzxNc4WKSqV0k/fsqaEpwHESOwuuNEa1LmZubfgr59eZ14Hd6neD2zz1+0yr+MHtDGv0bDntZcNRx8MpPdDjETniWY+m7YGtFsQRkrb47HSe012aZ8hKSlJZtB0zy6xf86fcnIHKxW9qVHehzIc7dZtC70fZUxi/q6bJWOG5kheXp6VE7tRI0dI506dTLpTx44yasRwk66LknwrZd6iDBk22opIan2t+6i8NWN19sXU5aQhUmC1zrTpOp97dH61u8LXF3ENWHftJJ32rJKlm6xxFxrEHHnRBXLZxRea4dKLhkqX8u//Ou10Gdh/aPn0M/u3NPmjLx4r/Vr6pPPQi+TScf2klcYWQsrSeVWr/qdXKrfL8AvkkmEDDymjZYt+cqaur2VwvkjKWur8F8jILuG31xZuX9147U+4cry2QfNros5MGaYeoq+3mqTna3Fx8EdIfdWWlNURsYu3acY9NN/7nhT+imbjS6WvaQKesWhW+S9OzmbgS7NHya+uypSFjibhKlhGRTN1c7GK0Ozcud6K5ure5TyzPNukh2Wuq2gybuafYP4o6f790O9c07y//J4jpkl5cHud227vZ+46q2m/mS/Y9Py9bYH1nH+UrHzeui+Jc//Nct7d0nVes35Hs3aTH26/tnvUqWPbvfIjHq8w+2n/UQIAAEDtaJlUKs+13yxle4olqdsx0mT6Y+LLiM+PxwcfvVNK3npUkjp3ksYPfuT5JdkOiDlbTapY893oPShvfHGDfLX5JxncpZnce04P6dA62D1XH7Zyk9Ud++6zu5c/hCWc3GmfSsvGKfLZzRXdy7VLd3KST+44K3iPydBxddxdX8ruAyWydsbxVo47Lb+41C9Lpx8jI+5b7PqQnIU3DpZ+t30uTdKSZMUdx1lT3DnrStN2nUVKO5eLxB/4crt20zZp0ihNsjKaS6P0VJN/sLBYthfslQMHiySna3aVgiT2dniJZvtsbg/COTpwTrxwXd+w00JF6uId+btu8HtXRffjPFno+C7k9b01dDm1feHjcemBGPrd0Ga+q8XQxTvabdNGL9cOa2uNxXE/XLY3lP3ddcGdq6XPLRMr7hGat0geeVnknKvdv5uW19Fr6yR3YvD+mdpK9hkJft9Xzv0Irsf9PpvO/dfv6S+7bIuJJVjfne18u/yKc+R1kYnB2MMdj84386jRo0aabrK2JUuXydz5H1pjsdGu3Jf33SNvvrlMdlnb4RQMmp0oLVbOKW9RaZYZIrLgfxfKRulipnf69mNzz0oNhE08o6Nsfest+WpXq0pdjYNl9ZHdgWlLdut45a7IGmDrv3uOvLa7b/k2FUhIGY7ytQw3drkapPPvXllp3+z9cd/e4L547evmkPpxqxtV1+rMVqle/Ftd96k2Obt622Lv8i3y/wH9gN3GfOOXiQAAAABJRU5ErkJggg==)
javah -d 【头文件生成路径】 -classpath 【java文件路径】-jni 【包名.类名】
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_remoteserver_RemoteService */ #ifndef _Included_com_example_remoteserver_RemoteService #define _Included_com_example_remoteserver_RemoteService #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_remoteserver_RemoteService * Method: stringFromJNI * Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_remoteserver_RemoteService_stringFromJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
3.根据生成的jni头文件建立 RemoteServiceJNI.c 文件实现其接口:
#include <jni.h> #include <string.h> #include <android/log.h> #define TAG "nano-jni" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_remoteserver_RemoteService * Method: stringFromJNI * Signature: ()Ljava/lang/String;
参数说明:
Native的对应函数名要以“Java_”开头,后面依次跟上Java的“package名”、“class名”、“函数名”,中间以下划线“_” 分割,在package名中的“.”也要改为“_”。
关于函数的参数和返回值也有相应的规则。对于Java中的基本类型如int 、double 、char 等,
在Native端都有相对应的类型来表示,如jint 、jdouble 、jchar 等;其他的对象类型则统统由jobject 来表示,
(String 是个例外,由于其使用广泛,故在Native代码中有jstring 这个类型来表示)。
而对于Java中的数组,在Native中由jarray 对应,具体到基本类型和一般对象类型的数组则有jintArray 等
和jobjectArray 分别对应(String 数组在这里没有例外,同样用jobjectArray 表示)。
另外在JNI的Native函数中,其前两个参数JNIEnv *和jobject 是必需的,前者是一个JNIEnv 结构体的指针,这个结构体中定义了很多JNI的接口函数指针,
使开发者可以使用JNI所定义的接口功能;后者指代的是调用这个JNI函数的Java对象,有点类似于C++中的this 指针。
在上述两个参数之后,还需要根据Java端的函数声明依次对应添加参数,如下Java中声明的JNI函数没有参数,则Native的对应函数只有类型为JNIEnv *和jobject 的两个参数。
*/ JNIEXPORT jstring JNICALL Java_com_example_remoteserver_RemoteService_stringFromJNI (JNIEnv *env, jobject thiz){ return (*env)->NewStringUTF(env, "Hi! Sheldon, I`m JNI ~"); } #ifdef __cplusplus } #endif
4.编译c文件生成so:
Android studio 的gradle3.0版本以下可以配置NDK编译c/cpp文件:
修改对应模块的build.gradle在defaultConfig中添加:
//gradle3.0以上已经不支持该方式 ndk { moduleName "libRemoteServiceJNI" //指定生成的so文件名 ldLibs "log", "z", "m" //添加log库 abiFilters "armeabi", "armeabi-v7a", "x86" //支持cpu的类型 }
而gradle3.0以上版本需要用CMake工具编译:
首先Android studio安装CMake工具:
然后同样在defaultConfig{}中添加编译参数:
// 使用Cmake工具 externalNativeBuild { cmake { cppFlags "" //生成多个版本的so文件 abiFilters 'armeabi-v7a' //,'arm64-v8a','x86','x86_64' } }
另外在defaultConfig{}的外一层即android{}中配置编译脚本的路径:
// 配置CMakeLists.txt路径 externalNativeBuild { cmake { path "CMakeLists.txt" //编译脚本 } }
比较关键的是CMakeLists.txt编译脚本,具体内容如下:
############################### #1.cmake verson,指定cmake版本 cmake_minimum_required(VERSION 3.4.1) #2.C++ 的编译选项是 CMAKE_CXX_FLAGS # 指定编译参数,可选 #SET(CMAKE_C_FLAGS "-Wno-error=format-security -Wno-error=pointer-sign") #3.设置cmake生成so输出的路径 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}) #4.包含头文件,导入第三方动态库 include_directories( ${CMAKE_SOURCE_DIR}/src/main/jni/include ) #5.指定源文件和编译生成so名及类型 # 生成在intermediates/cmake/和以上指定的目录下(指定的话build.gradle设置pickFirst避免冲突) add_library(RemoteServiceJNI SHARED ${CMAKE_SOURCE_DIR}/src/main/jni/RemoteServiceJNI.c) #6.设置需要生成so的第三方链接库 target_link_libraries( RemoteServiceJNI log android ) #添加子目录,将会调用子目录中的CMakeLists.txt #ADD_SUBDIRECTORY(one) #ADD_SUBDIRECTORY(two) ###############################
配置好编译环境后,点击make project生成so在remoteserver\build\intermediates\cmake\debug\obj\armeabi-v7a\libRemoteServiceJNI.so
在java中加载调用即可:
如果遇到: More than one file was found with OS independent path 'lib/armeabi-v7a/xxx.so' 的报错,则在build.gradle中的android {}里添加:
packagingOptions { //For Error: More than one file was found with OS independent path pickFirst 'lib/armeabi-v7a/libnano_socket.so' pickFirst 'lib/armeabi-v7a/libRemoteServiceJNI.so' }
完整工程已上传到GitHub: https://github.com/dragonforgithub/sheldon_aidl.git
posted on 2018-07-05 15:50 sheldon_blogs 阅读(3113) 评论(0) 编辑 收藏 举报