• No se han encontrado resultados

ITIL Una visión inicial

8.1 Materiales y Métodos Materiales

As in any ordinary NDK application, we’ll separate the code in modules. We’ll create a module called text-

formatter containing the library we want to port, and a second one called main, which will be in charge of the communication between Java and the TextFormatter class.

109

Running Objective-C in Android

33.2.1 The ItoaApp.mk and the ItoaModule.mk files

In a way similar to how the Android NDK uses the Application.mk and the Android.mk make files, Itoa has the ItoaApp.mk and the ItoaModule.mk files.

Inside our Android project directory, we’ll create a folder called jni. This jni folder will contain two make files, ItoaApp.mk and ItoaModule.mk, and two folders

to hold the modules—one folder for the

textformatter module and a second one for the main module. Inside each module folder, we’ll create an ItoaModule.mk file. The resulting directory structure can be seen in figure 33.2.

Let’s take a look at what we’ll place inside the ItoaApp.mk and ItoaModule.mk files. In the ItoaModule.mk make file, we’ll point to the module’s ItoaModule.mk files relative to the jni folder. The content is the following:

THIS_PATH := $(call my-dir)

include $(THIS_PATH)/main/ItoaModule.mk

include $(THIS_PATH)/TextFormatter/ItoaModule.mk

The ItoaApp.mk file contains more interesting information. The content is the following:

APP_IS_LIBRARY := true

B

Turn on library mode

APP_LIBRARY_BIN_PATH = ../libs/$(TARGET_ABI)

C

Set path for .so files

The default settings for the ItoaApp.mk file are enough for what we want to create. Since we don’t want to create an Android APK from the Objective-C code, we need to turn on the library mode

B

. The second setting is to set the path where the .so files will be saved

C

.

33.2.2 The textformatter module

The library to port is very simple. It only has a class method that returns an NSString *. The Objective-C code for this library is comprised of a .h file and a .m file. Here’s the code:

#import <Foundation/Foundation.h>

TextFormatter.h file

@interface TextFormatter: NSObject + (NSString *)format:(NSString *)text; @end

...

#import "TextFormatter.h"

TextFormatter.m file

@implementation TextFormatter

+ (NSString *)format:(NSString *)text { NSString *objc = @"Text from Objective-c";

NSString *string = [NSString stringWithFormat:@"%@ with %@",

objc, text];

TextFormatter.m file

return string; }

@end

As you can see, the library doesn’t need any modification. It’s just a .h and .m like you would use in an Objective-C application. Now let’s see how to configure the ItoaModule.mk file to compile this. Itoa NDK build scripts were derived from Android

NDK, but they were refactored. For example, the ItoaModule.mk file renames all the LOCAL_* variables to MODULE_*. The content of the make file is the following:

MODULE_PATH := $(call my-dir) include $(CLEAR_VARS)

MODULE_NAME := textformatter Module name

MODULE_SRC_FILES := \

TextFormatter.m Source files to compile

MODULE_C_INCLUDES += \

$(MODULE_PATH) \ Path to the include files

include $(BUILD_SHARED_LIBRARY)

Very similar to Android NDK make files, right?

33.2.3 The main module

The main module holds two source files:

 JNIOnLoad.cpp, where we’ll use the JNI_OnLoad method

 main.mm, where we’ll link JNI calls with the TextFormatter implementation Let’s create the JNIOnLoad.cpp file first:

#include <CoreFoundation/CFRuntime.h> #include <jni.h>

extern "C" {

jint JNI_OnLoad(JavaVM *vm, void *reserved) {

_CFInitialize(); Initialize CoreFoundation

extern void call_dyld_handlers(); Load Objective-C classes

call_dyld_handlers(); return JNI_VERSION_1_6; }

}

Because the virtual machine calls the JNI_OnLoad method when the native library is loaded, it’s a great place to make the initialization needed by Itoa.

111

Running Objective-C in Android

#include <jni.h> #import <Foundation/Foundation.h> #import <objc/runtime.h> #import <TextFormatter.h> extern "C" { jstring Java_com_manning_androidhacks_hack033_TextFormatter_formatString( JNIEnv* env, jobject thiz, jstring text)

B

TextFormatter JNI call

{

jstring result = NULL;

NSAutoreleasePool *pool = [NSAutoreleasePool new]; const char *nativeText = env->GetStringUTFChars(text, 0);

C

Convert jstring to NSString * NSString *objcText = [NSString stringWithUTF8String:nativeText]; env->ReleaseStringUTFChars(text, nativeText);

NSString *formattedText = [TextFormatter format: objcText]; result = env->NewStringUTF([formattedText UTF8String]);

D

Return a jstring with result [pool drain]; return result; } }

In the previous example, we have a mixture of C, C++, and Objective-C in the same file. From the method signature, we can learn that the TextFormatter Java native call will get a String as a parameter and will return a String

B

. Another interesting con- cept to learn here is that we can’t send the jstring we get as a parameter to the TextFormatter implementation directly. We need to convert the jstring to a char * and then convert that char * to an NSString *

C

. After calling the TextFormatter implementation, we’ll get an NSString * that will need to be converted to a jstring. This is done by converting it to char * first, and using the env to be able to return a jstring

D

.

The ItoaModule.mk file for main is the following: MODULE_PATH := $(call my-dir)

include $(CLEAR_VARS)

MODULE_NAME := main Module’s name

MODULE_SRC_FILES := \

JNIOnLoad.cpp \ Source files to compile

main.mm \

MODULE_C_INCLUDES += \ Include TextFormatter.h path

$(MODULE_PATH)/../textformatter \

MODULE_SHARED_LIBRARIES += textformatter textformatter dependency include $(BUILD_SHARED_LIBRARY)

Let’s talk about what the APP_SHARED_LIBRARIES is for

B

. For that variable, we used the macro $(TARGET_ITOA_LIBRARIES), which means that the .so files located at $ITOA_NDK/itoa/platform/arch-arm/usr/lib will be included in the libs directory. If you check what’s inside that directory, you’ll notice there are more .so files than we actually need. Before building it, you’ll need to delete (or move) the following librar- ies from $ITOA_NDK/itoa/platform/arch-arm/usr/lib:

 libcg.so  libcore.so  libjnipp.so  libuikit.so

33.2.4 Compiling

Now that we have all the native code in place, we need to compile all the .so files. Run this code

$ITOA_NDK/itoa-build from the jni folder.

ITOA-BUILD -C You can also use $ITOA_NDK/itoa-build -C /path/to/jni to avoid having to move to the jni folder.

After the compilation procedure finishes, we’ll get every .so file needed to run our Objective-C code in Android. In the next section, we’ll see how to call it from the Java layer.

Documento similar