Я использовал высокопроизводительную реализацию c ++, которую я загружаю с JNI.
Для более подробной информации, пожалуйста, напишите комментарий.
РЕДАКТИРОВАТЬ:
Требования для JNI - это Android NDK .Для Windows требуется дополнительно cygwin или что-то подобное.
Если вы выбрали Cygwin, я дам вам несколько небольших инструкций, как заставить его работать с NDK:
- Загрузите setup.exe из cygwin и запустите его.
- Нажмите Далее и выберите Установить из Интернета Подтвердите с помощью Далее .
- На следующих двух шагах настройте параметры по своему усмотрению и, как всегда, нажмите Далее .
- Выберите подключение к Интернету и ту же процедуру, что и на заключительных этапах.
- Страница загрузки попадется на глаза, выберите ее или возьмите только страницу загрузки, которая находится в вашей стране.Больше нечего сказать.
- Нам нужны пакеты make и gcc-g ++ .Вы можете найти их, используя поиск в левом верхнем углу, нажимая Пропустить , пока не отобразится версия и не будет выбрано первое поле.Сделайте то, что мы всегда делали после выбора.
- Вы получите информацию, что есть зависимости, которые необходимо устранить.Обычно нет необходимости делать это самостоятельно и подтверждать это.
- Загрузка и установка начались.
- Если вам нужно, вы можете создать ярлыки, в противном случае нажмите на исключительное Готово .
- Загрузите zip-файл и распакуйте NDK в путь без пробелов.
- Теперь вы можете запустить cygwin.
- Перейдите в NDK.Путь / cydrive дает вам все доступные диски, например,
cd /cygdrive/d
открывает диск с буквой D . - В корневой папке NDK вы можете выполнитьфайл ndk-build с
./ndk-build
.Должна быть ошибка, подобная Android NDK: Could not find application project directory !
.
. Для выполнения команды вам нужно перейти в проект Android.Итак, начнем с проекта.
Прежде чем мы сможем начать с поиска проекта реализации алгоритма хэширования на C / C ++.Я взял код с этого сайта CSHA1 .
Вы должны отредактировать исходный код для своих требований.
Теперь мы можем начать с JNI.
Вы создаете папку с именем jni в вашем проекте Android.Он содержит все собственные исходные файлы и Android.mk (подробнее об этом файле позже).
Скопируйте загруженные (и отредактированные) исходные файлы в эту папку.
Мой java-пакет называется de.dhbw.file.sha1 , поэтому я назвал мои исходные файлы похожими, чтобы их было легко найти.
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
# How the lib is called?
LOCAL_MODULE := SHA1Calc
# Which is your main SOURCE(!) file?
LOCAL_SRC_FILES := de_dhbw_file_sha1_SHA1Calc.cpp
include $(BUILD_SHARED_LIBRARY)
Java-код:
Я использовал AsyncTask с ProgressDialog , чтобы дать пользователю некоторую обратную связь о действии.
package de.dhbw.file.sha1;
// TODO: Add imports
public class SHA1HashFileAsyncTask extends AsyncTask<String, Integer, String> {
// [...]
static {
// loads a native library
System.loadLibrary("SHA1Calc");
}
// [...]
// native is the indicator for native written methods
protected native void calcFileSha1(String filePath);
protected native int getProgress();
protected native void unlockMutex();
protected native String getHash();
// [...]
}
Собственный код (C ++):
Помните доступ к переменным внутринативный код или другой способ использования потоков нуждается в синхронизации, иначе вы скоро получите ошибку сегментации!
Для использования JNI вы должны добавить #include <jni.h>
.
Для регистрации вставьте следующее:#include <android/log.h>
.
Теперь вы можете войти с помощью __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "Version [%s]", "19");
.
Первый аргумент - это тип сообщения, а второй - вызывающая библиотека.
Как видите, в моем коде был номер версии.Это очень полезно, потому что иногда сборщик apk не использует новые нативные библиотеки.Устранение неполадок может быть значительно сокращено, если неправильная версия включена.
Соглашения об именах в нативном коде немного сбивают с толку: Java_[package name]_[class name]_[method name]
.
Всегда указываются аргументы first to, но в зависимости от приложения вы должны различать:
func(JNIEnv * env, jobject jobj)
-> Вызов JNI является методом экземпляра func(JNIEnv * env, jclass jclazz)
-> Вызов JNI является статическим методом
Заголовок для метода calcFileSha1(...)
:
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_calcFileSha1(JNIEnv * env, jobject jobj, jstring file)
JDK поставляет двоичный файл javah.exe , который генерирует файл заголовка для собственного кода.Использование очень просто, просто назовите его с полным квалифицированным классом:
javah de.dhbw.file.sha1.SHA1HashFileAsyncTask
В моем случае я должен дополнительно указать bootclasspath , потому что я использую классы Android:javah -bootclasspath <path_to_the_used_android_api> de.dhbw.file.sha1.SHA1HashFileAsyncTask
Это будет сгенерированный файл:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class de_dhbw_file_sha1_SHA1HashFileAsyncTask */
#ifndef _Included_de_dhbw_file_sha1_SHA1HashFileAsyncTask
#define _Included_de_dhbw_file_sha1_SHA1HashFileAsyncTask
#ifdef __cplusplus
extern "C" {
#endif
#undef de_dhbw_file_sha1_SHA1HashFileAsyncTask_ERROR_CODE
#define de_dhbw_file_sha1_SHA1HashFileAsyncTask_ERROR_CODE -1L
#undef de_dhbw_file_sha1_SHA1HashFileAsyncTask_PROGRESS_CODE
#define de_dhbw_file_sha1_SHA1HashFileAsyncTask_PROGRESS_CODE 1L
/*
* Class: de_dhbw_file_sha1_SHA1HashFileAsyncTask
* Method: calcFileSha1
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_calcFileSha1
(JNIEnv *, jobject, jstring);
/*
* Class: de_dhbw_file_sha1_SHA1HashFileAsyncTask
* Method: getProgress
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_getProgress
(JNIEnv *, jobject);
/*
* Class: de_dhbw_file_sha1_SHA1HashFileAsyncTask
* Method: unlockMutex
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_unlockMutex
(JNIEnv *, jobject);
/*
* Class: de_dhbw_file_sha1_SHA1HashFileAsyncTask
* Method: getHash
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_de_dhbw_file_sha1_SHA1HashFileAsyncTask_getHash
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Вы можете изменить файл без дополнительного уведомления.Но не используйте javah
снова!
Класс и методы
Чтобы получить экземпляр класса, вы можете использовать jclass clz = callEnv->FindClass(CALL_CLASS);
.В этом случае CALL_CLASS
полный путь к классу de / dhbw / file / sha1 / SHA1HashFileAsyncTask .
Чтобы найти метод, вам нужен JNIEnv и экземпляр класса:
jmethodID midSet = callEnv->GetMethodID(callClass, "setFileSize", "(J)V");
Первый аргумент - это экземпляр класса, второй - имя методаи третье - это сигнатура метода.
Сигнатура, которую вы можете получить с помощью двоичного файла JDK javap.exe .Просто вызовите его, указав полный путь к классу fe javap -s de.dhbw.file.sha1.SHA1HashFileAsyncTask
.
. Вы получите такой результат, как:
Compiled from "SHA1HashFileAsyncTask.java"
public class de.dhbw.file.sha1.SHA1HashFileAsyncTask extends android.os.AsyncTas
k<java.lang.String, java.lang.Integer, java.lang.String> {
[...]
static {};
Signature: ()V
public de.dhbw.file.sha1.SHA1HashFileAsyncTask(android.content.Context, de.dhb
w.file.sha1.SHA1HashFileAsyncTask$SHA1AsyncTaskListener);
Signature: (Landroid/content/Context;Lde/dhbw/file/sha1/SHA1HashFileAsyncTas
k$SHA1AsyncTaskListener;)V
protected native void calcFileSha1(java.lang.String);
Signature: (Ljava/lang/String;)V
protected native int getProgress();
Signature: ()I
protected native void unlockMutex();
Signature: ()V
protected native java.lang.String getHash();
Signature: ()Ljava/lang/String;
[...]
public void setFileSize(long);
Signature: (J)V
[...]
}
Если метод найден, переменная не равна 0.
Вызов метода очень прост:
callEnv->CallVoidMethod(callObj, midSet, size);
Первый аргумент - это заданный jobject из метода "main", и я думаю, что остальные понятны.
Помните, что вы можете вызывать из нативного кода хотя частные методы класса, потому что нативный код является его частью!
Строки
Данная строка будет преобразована со следующим кодом:
jboolean jbol;
const char *fileName = env->GetStringUTFChars(file, &jbol);
И другим способом:
TCHAR* szReport = new TCHAR;
jstring result = callEnv->NewStringUTF(szReport);
Это может быть любая char*
переменная.
Исключения
Может быть выдано с помощью JNIEnv :
callEnv->ThrowNew(callEnv->FindClass("java/lang/Exception"),
"Hash generation failed");
Вы также можете проверить, возникла ли исключительная ситуация, также с помощью JNIEnv :
if (callEnv->ExceptionOccurred()) {
callEnv->ExceptionDescribe();
callEnv->ExceptionClear();
}
Технические характеристики
Build / Clean
Build
После того, как мы создали все файлыи заполняя их содержимым, мы можем его построить.
Откройте cygwin, перейдите к корню проекта и выполните оттуда ndk-build , который находится в корне NDK.
Это запуститскомпилируйте, в случае успеха вы получите такой вывод:
$ /cygdrive/d/android-ndk-r5c/ndk-build
Compile++ thumb : SHA1Calc <= SHA1Calc.cpp
SharedLibrary : libSHA1Calc.so
Install : libSHA1Calc.so => libs/armeabi/libSHA1Calc.so
Если возникнет какая-либо ошибка, вы получите типичный вывод от компилятора.
Очистите
Откройте Cygwin, включите ваш проект Android и выполните команду /cygdrive/d/android-ndk-r5c/ndk-build clean
.
Build apk
После того, как вы соберете роднойбиблиотеки вы можете построить свой проект.Я обнаружил, что чисто, выгодно использовать функцию eclipse clean project .
Отладка
Отладка Java-кода не отличается от предыдущей.
Отладка кода на С ++ последует в следующий раз.