如何从C ++代码请求Android NDK摄像机许可?

时间:2019-03-08 11:54:48

标签: android c++ android-ndk

我正在用纯c ++编写应用程序,并且我有打开相机的代码。 并将AndroidManifest.xml设置为:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera2" android:required="true" />

首次运行该应用程序时,它不会提示您打开权限。安装后,我必须手动进行操作, 设置->应用程序->“ MyApp”->权限。

如何在不引入Java代码的情况下以c ++提供提示? 非常感谢所有帮助。

2 个答案:

答案 0 :(得分:1)

所以我也看到了。

  1. 要手动执行此操作,还可以通过命令行使用adb shell pm grant com.package.name android.permission.CAMERA

  2. 检查权限是否存在adb shell dumpsys package com.package.name

  3. This is the series of steps to ask for permissions with Java

  4. 要弄清楚如何在不使用Java的情况下执行此操作,您需要深入研究AOSP才能发现它的working under the hood ...并非无关紧要,也找不到示例。 / p>

答案 1 :(得分:1)

这可以使用JNI调用来完成。有关READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE(可轻松适应相机烫发)的信息,请参见下面的示例。

在应用程序启动时调用函数:

 check_android_permissions(struct android_app* app) 
(参见下面的源代码)。

几个陷阱:

  • android.Manifest.permission是嵌套在android.Manifest中的类, 因此其JNI名称为“ android / Manifest $ permission”。
  • 我没有设法 访问ContextCompat(android.support.v4.content.ContextCompat)和 来自JNI的ActivityCompat(android.support.v4.app.ActivityCompat),因此 我使用了Context(android.content.Context)和Activity (android.app.Activity)。因此,需要使用Android API级别23(棉花糖,2015年5月)。
  • 需要在类中检索常量,尤其是READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE是android.Manifest.permission中的静态字符串,而PERMISSION_GRANTED是android.content.pm.PackageManager中的静态整数。
  • 当用户单击“不再询问我”按钮时,我没有实现如何处理,这将需要实现onRequestPermissionsResult()回调。


/**
 * \brief Gets the internal name for an android permission.
 * \param[in] lJNIEnv a pointer to the JNI environment
 * \param[in] perm_name the name of the permission, e.g.,
 *   "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE".
 * \return a jstring with the internal name of the permission,
 *   to be used with android Java functions 
 *   Context.checkSelfPermission() or Activity.requestPermissions()
 */
jstring android_permission_name(JNIEnv* lJNIEnv, const char* perm_name) {
    // nested class permission in class android.Manifest,
    // hence android 'slash' Manifest 'dollar' permission
    jclass ClassManifestpermission = lJNIEnv->FindClass(
       "android/Manifest$permission"
    );
    jfieldID lid_PERM = lJNIEnv->GetStaticFieldID(
       ClassManifestpermission, perm_name, "Ljava/lang/String;"
    );
    jstring ls_PERM = (jstring)(lJNIEnv->GetStaticObjectField(
        ClassManifestpermission, lid_PERM
    )); 
    return ls_PERM;
}

/**
 * \brief Tests whether a permission is granted.
 * \param[in] app a pointer to the android app.
 * \param[in] perm_name the name of the permission, e.g.,
 *   "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE".
 * \retval true if the permission is granted.
 * \retval false otherwise.
 * \note Requires Android API level 23 (Marshmallow, May 2015)
 */
bool android_has_permission(struct android_app* app, const char* perm_name) {
    JavaVM* lJavaVM = app->activity->vm;
    JNIEnv* lJNIEnv = nullptr; 
    bool lThreadAttached = false;

    // Get JNIEnv from lJavaVM using GetEnv to test whether
    // thread is attached or not to the VM. If not, attach it
    // (and note that it will need to be detached at the end
    //  of the function).
    switch (lJavaVM->GetEnv((void**)&lJNIEnv, JNI_VERSION_1_6)) {
      case JNI_OK:
        break;
      case JNI_EDETACHED: {
        jint lResult = lJavaVM->AttachCurrentThread(&lJNIEnv, nullptr);
        if(lResult == JNI_ERR) {
          throw std::runtime_error("Could not attach current thread");
        }
        lThreadAttached = true;
      } break;
      case JNI_EVERSION:
        throw std::runtime_error("Invalid java version");
    }

    bool result = false;

    jstring ls_PERM = android_permission_name(lJNIEnv, perm_name);

    jint PERMISSION_GRANTED = jint(-1);
    {
       jclass ClassPackageManager = lJNIEnv->FindClass(
          "android/content/pm/PackageManager"
       );
       jfieldID lid_PERMISSION_GRANTED = lJNIEnv->GetStaticFieldID(
          ClassPackageManager, "PERMISSION_GRANTED", "I"
       );
       PERMISSION_GRANTED = lJNIEnv->GetStaticIntField(
          ClassPackageManager, lid_PERMISSION_GRANTED
       );
    }
    {
       jobject activity = app->activity->clazz;
       jclass ClassContext = lJNIEnv->FindClass(
          "android/content/Context"
       );
       jmethodID MethodcheckSelfPermission = lJNIEnv->GetMethodID(
          ClassContext, "checkSelfPermission", "(Ljava/lang/String;)I"
       );
       jint int_result = lJNIEnv->CallIntMethod(
           activity, MethodcheckSelfPermission, ls_PERM
       );
       result = (int_result == PERMISSION_GRANTED);
    }

    if(lThreadAttached) {
      lJavaVM->DetachCurrentThread();
    }

    return result;
}

/**
 * \brief Query file permissions.
 * \details This opens the system dialog that lets the user
 *  grant (or deny) the permission.
 * \param[in] app a pointer to the android app.
 * \note Requires Android API level 23 (Marshmallow, May 2015)
 */
void android_request_file_permissions(struct android_app* app) {
    JavaVM* lJavaVM = app->activity->vm;
    JNIEnv* lJNIEnv = nullptr; 
    bool lThreadAttached = false;

    // Get JNIEnv from lJavaVM using GetEnv to test whether
    // thread is attached or not to the VM. If not, attach it
    // (and note that it will need to be detached at the end
    //  of the function).
    switch (lJavaVM->GetEnv((void**)&lJNIEnv, JNI_VERSION_1_6)) {
      case JNI_OK:
        break;
      case JNI_EDETACHED: {
        jint lResult = lJavaVM->AttachCurrentThread(&lJNIEnv, nullptr);
        if(lResult == JNI_ERR) {
          throw std::runtime_error("Could not attach current thread");
        }
        lThreadAttached = true;
      } break;
      case JNI_EVERSION:
        throw std::runtime_error("Invalid java version");
      }

    jobjectArray perm_array = lJNIEnv->NewObjectArray(
      2,
      lJNIEnv->FindClass("java/lang/String"),
      lJNIEnv->NewStringUTF("")
    );

    lJNIEnv->SetObjectArrayElement(
      perm_array, 0,
      android_permission_name(lJNIEnv, "READ_EXTERNAL_STORAGE")
    );

    lJNIEnv->SetObjectArrayElement(
      perm_array, 1,
      android_permission_name(lJNIEnv, "WRITE_EXTERNAL_STORAGE")        
    );

    jobject activity = app->activity->clazz;

    jclass ClassActivity = lJNIEnv->FindClass(
       "android/app/Activity"
    );

    jmethodID MethodrequestPermissions = lJNIEnv->GetMethodID(
       ClassActivity, "requestPermissions", "([Ljava/lang/String;I)V"
    );

    // Last arg (0) is just for the callback (that I do not use)
    lJNIEnv->CallVoidMethod(
       activity, MethodrequestPermissions, perm_array, 0
    );

    if(lThreadAttached) {
       lJavaVM->DetachCurrentThread();
    }
}

void check_android_permissions(struct android_app* app) {
    bool OK = android_has_permission(
       app, "READ_EXTERNAL_STORAGE"
    ) && android_has_permission(
       app, "WRITE_EXTERNAL_STORAGE"
    );
    if(!OK) {
       android_request_file_permissions(app);
    }
}