jclass FindClassInFiles()

in app/src/util_android.cc [1588:1702]


jclass FindClassInFiles(
    JNIEnv* env, jobject activity_object,
    const std::vector<internal::EmbeddedFile>& embedded_files,
    const char* class_name) {
  if (!embedded_files.size()) {
    return nullptr;
  }

  jobject cache_dir = env->CallObjectMethod(
      activity_object, activity::GetMethodId(activity::kGetCacheDir));
  CheckAndClearJniExceptions(env);
  jobject cache_dir_path_jstring = env->CallObjectMethod(
      cache_dir, file::GetMethodId(file::kGetAbsolutePath));
  CheckAndClearJniExceptions(env);
  std::string cache_dir_path =
      firebase::util::JniStringToString(env, cache_dir_path_jstring);

#if defined(FIREBASE_ANDROID_FOR_DESKTOP)
  static const char kPathSeparator = '/';

  jobject cache_uri =
      env->CallObjectMethod(cache_dir, file::GetMethodId(file::kToUri));
  CheckAndClearJniExceptions(env);
  env->DeleteLocalRef(cache_dir);
  jobject cache_url =
      env->CallObjectMethod(cache_uri, java_uri::GetMethodId(java_uri::kToUrl));
  CheckAndClearJniExceptions(env);
  env->DeleteLocalRef(cache_uri);
  jobjectArray url_path_array =
      env->NewObjectArray(embedded_files.size(), url::GetClass(), nullptr);
  for (int i = 0; i < embedded_files.size(); ++i) {
    jstring embedded_file_string = env->NewStringUTF(embedded_files[i].name);
    jobject jar_url =
        env->NewObject(url::GetClass(), url::GetMethodId(url::kConstructor),
                       cache_url, embedded_file_string);
    env->SetObjectArrayElement(url_path_array, i, jar_url);
    env->DeleteLocalRef(jar_url);
    env->DeleteLocalRef(embedded_file_string);
  }
  env->DeleteLocalRef(cache_url);

  jobject class_loader_obj = env->NewObject(
      url_class_loader::GetClass(),
      url_class_loader::GetMethodId(url_class_loader::kConstructor),
      url_path_array, GetParentLoader());
  env->DeleteLocalRef(url_path_array);

  std::string class_name_str(class_name);
  std::replace(class_name_str.begin(), class_name_str.end(), kPathSeparator,
               '.');
  LogDebug("Load class %s (a.k.a. %s)", class_name_str.c_str(), class_name);
  jstring class_name_object = env->NewStringUTF(class_name_str.c_str());
  jclass loaded_class = static_cast<jclass>(env->CallObjectMethod(
      class_loader_obj,
      url_class_loader::GetMethodId(url_class_loader::kLoadClass),
      class_name_object));
  CheckAndClearJniExceptions(env);
#else   // defined(FIREBASE_ANDROID_FOR_DESKTOP)
  static const char kPathSeparator = '/';
  static const char kDexPathSeparator = ':';
  // Older versions of Android don't have GetCodeCacheDir, so fall back to
  // GetCacheDir.
  const jmethodID get_code_cache_dir_method_id =
      activity::GetMethodId(activity::kGetCodeCacheDir) != 0
          ? activity::GetMethodId(activity::kGetCodeCacheDir)
          : activity::GetMethodId(activity::kGetCacheDir);
  jobject code_cache_dir =
      env->CallObjectMethod(activity_object, get_code_cache_dir_method_id);
  CheckAndClearJniExceptions(env);
  jobject code_cache_dir_path = env->CallObjectMethod(
      code_cache_dir, file::GetMethodId(file::kGetAbsolutePath));
  CheckAndClearJniExceptions(env);
  env->DeleteLocalRef(code_cache_dir);
  env->DeleteLocalRef(cache_dir);

  std::string dex_path;
  for (std::vector<internal::EmbeddedFile>::const_iterator it =
           embedded_files.begin();
       it != embedded_files.end(); ++it) {
    dex_path += cache_dir_path + kPathSeparator + std::string(it->name);
    dex_path.push_back(kDexPathSeparator);
  }
  dex_path.pop_back();

  LogDebug("Set class path to %s", dex_path.c_str());

  jstring dex_path_string = env->NewStringUTF(dex_path.c_str());
  jobject class_loader_obj = env->NewObject(
      dex_class_loader::GetClass(),
      dex_class_loader::GetMethodId(dex_class_loader::kConstructor),
      dex_path_string, code_cache_dir_path, nullptr, GetParentLoader());
  env->DeleteLocalRef(code_cache_dir_path);
  env->DeleteLocalRef(dex_path_string);

  LogDebug("Load class %s", class_name);
  jstring class_name_object = env->NewStringUTF(class_name);
  jclass loaded_class = static_cast<jclass>(env->CallObjectMethod(
      class_loader_obj,
      dex_class_loader::GetMethodId(dex_class_loader::kLoadClass),
      class_name_object));
  CheckAndClearJniExceptions(env);
#endif  // defined(FIREBASE_ANDROID_FOR_DESKTOP)

  if (!env->ExceptionCheck()) {
    LogDebug("%s loaded.", class_name);
    AddClassLoader(env, class_loader_obj);
  } else {
    env->ExceptionClear();
    LogDebug("%s *not* loaded", class_name);
    env->DeleteLocalRef(loaded_class);
    env->DeleteLocalRef(class_loader_obj);
  }
  env->DeleteLocalRef(class_name_object);
  return loaded_class;
}