Skip to content

proposal: x/mobile: add permission request on android #50104

Open
@MatejMagat305

Description

@MatejMagat305

What version of Go are you using (go version)?

go version go1.17.3 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/matejmag305/.cache/go-build"
GOENV="/home/matejmag305/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/matejmag305/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/matejmag305/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/matejmag305/go_sdk/go1.17.3"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/matejmag305/go_sdk/go1.17.3/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.3"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build16419202=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I was found problem: is no easy way how request permission by runtime..........

More story

I m interesting in programing android apps with go, I have created small library for my (experimental) project, the library is trying implement bluetooth socket ....., but I have problem with manifest (androids ignore Bluetooth permission........), I was trying to fix(by runtime), then I realize that there is not easy way how request permission by runtime.........., I was writing this problem to fyne-io/fyne, which forms the graphics library of my experimental project, but now I think it is issue to gomobile.

Solution Proposal

The Solution would be use existing way how from ndk request permission. It would add two functions to programmer (user) interface. It is support with ndk solution:

More story

Add to code to mobile/app/android.c or somewhere where it pass best a few functions(or one, it depends on ordering of code) to background (in the fact I suggest the implementation solution, but it will be on implementation team how it will works) and two functions to user interface (the reason of this topic), pattern of these functions is the first answer in ndk request camera

Exported GO side (main Proposal)

func RequestPermision(permission string) Next code would use RunOnJVM from "mobileinit" package, it would have argument like "permission string" but in final version it could be "permission int", the code call `C.android_permissions(env, n)`, which could be void or return something, in further code is void ...
func RequestPermision(permission string){
	n := C.CString(permission)
	mobileinit.RunOnJVM(func(vm, jniEnv, ctx uintptr) error {
		env := (*C.JNIEnv)(unsafe.Pointer(jniEnv))
		C.android_permissions(env, n)// or result := ...
		return nil // or return result
	})
	C.free(unsafe.Pointer(n))
}

Other OS (IOS) should have: func RequestPermision(permission string){} // dummy function.
Of course probably IOS has similar system of permission, but I haven't experience for suggest any example...........

func IsPermision(permission string) bool

The next exported function would have similar situation with argument like previous one - I do not know whether solution of type functions is the best..... and in the fact it: it would unnecessary function, could be skipped because it could be execute at the beginning android_permissions, but sometime you want only find out whether permission is given and nothing more, therefore I mention this option .....

func IsPermision(permission string) bool{
	n := C.CString(permission)
        var result bool
	mobileinit.RunOnJVM(func(vm, jniEnv, ctx uintptr) error {
		env := (*C.JNIEnv)(unsafe.Pointer(jniEnv))
		result = bool(android_has_permission( env, perm_name))
		return nil // or return result
	})
	C.free(unsafe.Pointer(n))
        return result
}

Unexported - Background C side (of course only example how it could be done)

void android_permissions(JNIEnv* env, char* perm_name) In this example it is void, but it could be string (char*) or bool and of course argument could be int, at the beginning function control whether permission would be granted and after that if it was not granted it would be call function to "real" request.:
void android_permissions(JNIEnv* env,  char* perm_name) {// or bool or string to indentify error
    bool OK = android_has_permission(
       env, perm_name
    ) ;
    if(!OK) {
       android_request_permission(env,perm_name ); // or return  android_request_file_permissions(env,perm_name ); due to error
    }
}
void android_request_permission(JNIEnv* env, char* permissions) It would be call ndk java api to granted permission.
void android_request_permission(JNIEnv* env, char* permissions) { // or bool or string to reference error
    jobjectArray perm_array = (*env)->NewObjectArray(env,
      2,
      find_class(env, "java/lang/String"),
      (*env)->NewStringUTF(env, "")
    );
    (*env)->SetObjectArrayElement(env,
          perm_array, 1,
          android_permission_name(env, permissions)
        );
    (*env)->CallVoidMethod(
       current_class, request_permissions, perm_array, 0
    );
}
bool android_has_permission(JNIEnv* env, const char* perm_name) The function to check whether permission is granted:
bool android_has_permission(JNIEnv* env, const char* perm_name) {  
    bool result = false;
    jstring ls_PERM = android_permission_name(env, perm_name);
    int PERMISSION_GRANTED = -1;
    {
       jclass ClassPackageManager = find_class(env, "android/content/pm/PackageManager" );
       jfieldID lid_PERMISSION_GRANTED = (*env)->GetStaticFieldID(env,
          ClassPackageManager, "PERMISSION_GRANTED", "I"
       );
       PERMISSION_GRANTED = (*env)->GetStaticIntField(env,
          ClassPackageManager, lid_PERMISSION_GRANTED
       );
    }
    {
       jclass ClassContext = find_class(env,  "android/content/Context"   );
       jmethodID MethodcheckSelfPermission = find_method(env, ClassContext,
       "checkSelfPermission", "(Ljava/lang/String;)I" );
       int int_result =(int) (*env)->CallIntMethod(env,
           current_class, MethodcheckSelfPermission, ls_PERM
       );
       result = (int_result == PERMISSION_GRANTED);
    }
    return result;
}
jclass android_permission_name(JNIEnv* env, const char* perm_name) The function to get permission class from (char*) string:
jclass android_permission_name(JNIEnv* env, const char* perm_name) {
    // nested class permission in class android.Manifest,
    // hence android 'slash' Manifest 'dollar' permission
    jclass ClassManifestpermission = find_class(env, "android/Manifest$permission");
    jfieldID lid_PERM = (*env)->GetStaticFieldID(env,
       ClassManifestpermission, perm_name, "Ljava/lang/String;"
    );
    jclass ls_PERM = (jclass)((*env)->GetStaticObjectField(env,
        ClassManifestpermission, lid_PERM
    ));
    return ls_PERM;
}
static jmethodID request_permissions And of course some functions could be "extracted" at init:
static jmethodID request_permissions;  
//which init in function ANativeActivity_onCreate

Like show: https://github.com/golang/mobile/blob/4e6c2922fdeed32d3596616518aaee7b0d79ce55/app/android.c#L71
and https://github.com/golang/mobile/blob/4e6c2922fdeed32d3596616518aaee7b0d79ce55/app/android.c#L78


I m sorry for my English, which is not best.......

EDITED:

Of course there is further reason, why implement this request: dangerous permission: https://developer.android.com/training. Yes I know that golang isn't primary for android and majority of request will never need (because missing API), but there are some permissions, which gomobile could use ..............., for example above mentioned Bluetooth.

ADDED LATER:

I have made some prototype of this (it is working on my android simulator): https://github.com/MatejMagat305/golang-prototype-permision (without adding to current code, only use function RunOnJVM) - it is only prototype which probably contains memory leak and maybe it should be good added or change functions to request multiple strings ............... And yes, something similar is on IOS, but I haven't suitable device, experience and internet claim that work a little bit diferent

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.ProposalmobileAndroid, iOS, and x/mobile

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions