在 Android 中使用 C++/JNI 迭代 ZipFile$ZipEntryIterator 列表

问题描述 投票:0回答:1

我对 android 中的 cpp 或 jni 相当陌生。我在 kotlin 中有几行代码,我想将其移至 cpp,原因是希望以更安全的方式进行验证。

Kotlin 代码:

val entries = ZipFile(context.packageCodePath).entries().toList()
var totalCrc = 0L
for (entry in entries) {
   if (entry.name.startsWith(DEX_FILENAME)) totalCrc += entry.crc
}

我可以在cpp中实现什么:

jclass zipFileClass = env->FindClass("java/util/zip/ZipFile");
    jmethodID zipFileConstructor = env->GetMethodID(zipFileClass, "<init>", "(Ljava/lang/String;)V");
    jobject zipFileObject = env->NewObject(zipFileClass, zipFileConstructor, packageCodePath);
    jmethodID methodId = env->GetMethodID(zipFileClass, "entries", "()Ljava/util/Enumeration;");
    jobject zipFileList = env->CallObjectMethod(zipFileObject, methodId);

    jclass ZipEntryIteratorClass = env->FindClass("java/util/zip/ZipFile$ZipEntryIterator");

**    // This line doesnt have any error from the compiler. **
    jmethodID mid_Iterator_hasNext = env->GetMethodID(ZipEntryIteratorClass, "hasMoreElements", "()Z");
     
**    // I get error at this line, for some reason jni layer is not able to find the nextElement method**
    jmethodID mid_Iterator_next = env->GetMethodID(ZipEntryIteratorClass, "nextElement", "()Ljava/util/zip/ZipEntry;");
**    // This line also is able to run without any exception. **
    jboolean hasMoreElements = env->CallBooleanMethod(zipFileList, mid_Iterator_hasNext);

**// Of course below code doesnt work, due to the exception**

    //jobject v = env->CallObjectMethod(zipFileList, mid_Iterator_next);
    //env->DeleteLocalRef(v);

**// This is the logic which I would eventually have to iterate through the items.**
    //while (hasMoreElements) {
        //jobject v = env->CallObjectMethod(zipFileList, mid_Iterator_next);
        // Do something with `v`

        // Avoid overflowing the local reference table if legList gets large
        //env->DeleteLocalRef(v);
    //}

我得到的例外是:

runtime.cc:677] JNI DETECTED ERROR IN APPLICATION: JNI CallBooleanMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method "Ljava/util/zip/ZipFile$ZipEntryIterator;.nextElement()Ljava/util/zip/ZipEntry;"
                                                                                                    runtime.cc:677]   at boolean com.something.else.RandomScreenActivity.validateChecksum(java.lang.String) (RandomScreenActivity.kt:-2)
                                                                                                    runtime.cc:677]   at void com.something.else.RandomScreenActivity.onCreate(android.os.Bundle) (RandomScreenActivity.kt:72)
                                                                                                    runtime.cc:677]   at void android.app.Activity.performCreate(android.os.Bundle, android.os.PersistableBundle) (Activity.java:8051)
                                                                                                    runtime.cc:677]   at void android.app.Activity.performCreate(android.os.Bundle) (Activity.java:8031)
                                                                                                    runtime.cc:677]   at void android.app.Instrumentation.callActivityOnCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1329)
                                                                                                    runtime.cc:677]   at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:3608)
                                                                                                    runtime.cc:677]   at android.app.Activity android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.app.servertransaction.PendingTransactionActions, android.content.Intent) (ActivityThread.java:3792)
                                                                                                    runtime.cc:677]   at void android.app.servertransaction.LaunchActivityItem.execute(android.app.ClientTransactionHandler, android.os.IBinder, android.app.servertransaction.PendingTransactionActions) (LaunchActivityItem.java:103)
                                                                                                    runtime.cc:677]   at void android.app.servertransaction.TransactionExecutor.executeCallbacks(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:135)
                                                                                                    runtime.cc:677]   at void android.app.servertransaction.TransactionExecutor.execute(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:95)
                                                                                                    runtime.cc:677]   at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:2210)
                                                                                                    runtime.cc:677]   at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:106)
                                                                                                    runtime.cc:677]   at boolean android.os.Looper.loopOnce(android.os.Looper, long, int) (Looper.java:201)
                                                                                                    runtime.cc:677]   at void android.os.Looper.loop() (Looper.java:288)
                                                                                                    runtime.cc:677]   at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:7839)
                                                                                                    runtime.cc:677]   at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
                                                                                                    runtime.cc:677]   at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:548)
                                                                                                    runtime.cc:677]   at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:1003)
                                                                                                    runtime.cc:677] 
                                                                                                    runtime.cc:677]     in call to CallBooleanMethodV
                                                                                                    runtime.cc:677]     from boolean RandomScreenActivity.validateChecksum(java.lang.String)

此外,java.util.ZipFIle 类中的 ZipEntryIterator 类具有以下可用于迭代项目的方法:

private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
        private int i = 0;

        public ZipEntryIterator() {
            ensureOpen();
        }

        public boolean hasMoreElements() {
            return hasNext();
        }

        public boolean hasNext() {
            synchronized (ZipFile.this) {
                ensureOpen();
                return i < total;
            }
        }

        public ZipEntry nextElement() {
            return next();
        }

        public ZipEntry next() {
            synchronized (ZipFile.this) {
                ensureOpen();
                if (i >= total) {
                    throw new NoSuchElementException();
                }
                long jzentry = getNextEntry(jzfile, i++);
                if (jzentry == 0) {
                    String message;
                    if (closeRequested) {
                        message = "ZipFile concurrently closed";
                    } else {
                        message = getZipMessage(ZipFile.this.jzfile);
                    }
                    throw new ZipError("jzentry == 0" +
                                       ",\n jzfile = " + ZipFile.this.jzfile +
                                       ",\n total = " + ZipFile.this.total +
                                       ",\n name = " + ZipFile.this.name +
                                       ",\n i = " + i +
                                       ",\n message = " + message
                        );
                }
                ZipEntry ze = getZipEntry(null, jzentry);
                freeEntry(jzfile, jzentry);
                return ze;
            }
        }
    }

有什么建议如何迭代 ZipEntryIterator 列表吗?

android java-native-interface
1个回答
0
投票

在我的虚拟 Android 设备上,我收到以下 logcat 条目:

访问隐藏方法

Ljava/util/zip/ZipFile$ZipEntryIterator;nextElement()Ljava/util/zip/ZipEntry;
(max-target-r,JNI,拒绝)

这让我认为你应该坚持使用通用的

Enumeration
界面。
ZipFile
类返回一个通用的
Enumeration
接口,该接口仅返回
Object
。所以:

jmethodID mid_Iterator_next = env->GetMethodID(ZipEntryIteratorClass, "nextElement", "()Ljava/lang/Object;");
© www.soinside.com 2019 - 2024. All rights reserved.