Lamelynx / GodotGetImagePlugin-Android

Godot plugin to select image from gallery or camera on Android device.
MIT License
71 stars 4 forks source link

Android 13 #15

Closed MingTsv closed 8 months ago

MingTsv commented 1 year ago

it doesn't work on android 13

finepointcgi commented 1 year ago

I just tested this on android 13 with a google pixel 5 it seems to work for me. What error are you getting?

Edit: It does seem to be broken it looks like godot is not requesting the android.permission.READ_EXTERNAL_STORAGE which seems to be a godot bug.

MingTsv commented 1 year ago

i have given READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE and MANAGE_EXTERNAL_STORAGE permission to my game but when I click the button to run getGalleyImage() it doesn't show anything. I'm using godot 3.5 and your 3.4 plugin

Lamelynx commented 1 year ago

For best compatibility, you need to have the same vesion on the plugin as the version on Godot.

MingTsv commented 1 year ago

I can't find my version in your plugin

finepointcgi commented 1 year ago

For best compatibility, you need to have the same vesion on the plugin as the version on Godot.

I pulled the 4.0.3 aab updated the api to 31 build tools are now 30 and updated kotlin to 1.6.0. I don't think its the plugin I think its Godot itself. See: https://github.com/godotengine/godot/issues/60635

MingTsv commented 1 year ago

Để tương thích tốt nhất, bạn cần có cùng phiên bản trên plugin với phiên bản trên Godot.

Tôi đã kéo aab 4.0.3 đã cập nhật api lên 31 công cụ xây dựng hiện là 30 và cập nhật kotlin lên 1.6.0. Tôi không nghĩ đó là plugin mà tôi nghĩ đó là Godot. Xem: godotengine/godot#60635

Did you fix it yet? Please help me if you have a solution to this problem

blurrred commented 1 year ago

I think this is related to API changes in Android 13. Apparently android.permission.READ_EXTERNAL_STORAGE was split into multiple different permissions. https://developer.android.com/about/versions/14/changes/partial-photo-video-access I have tried granting my app android.permission.READ_MEDIA_IMAGES with a custom permission in Godot, but getGalleryImages() still fails to bring up the image selection interface.

Lamelynx commented 1 year ago

I'm looking into implentering Photo picker , it might fix the problem.

blurrred commented 1 year ago

I was able to implement photo picker in Android (including 13) with the following code:

    public void getGalleryImage() {
        Log.d("godot", "Call - getGalleryImage");
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(getActivity(), intent, 101, null);
    }

    public void onMainActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            // Get the URI of the selected media file
            Uri imageUri = data.getData();
            Bitmap bitmap;
            try {
                InputStream imageStream = getGodot().getContext().getContentResolver().openInputStream(imageUri);
                bitmap = BitmapFactory.decodeStream(imageStream);
                imageStream.close();
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            Dictionary imageDict = new Dictionary();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream);
            try {
                stream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            imageDict.put("0", stream.toByteArray());
            emitSignal("image_request_completed", imageDict);
        }
    }

    @NonNull
    @Override
    public Set<SignalInfo> getPluginSignals() {
        Set<SignalInfo> signals = new ArraySet<>();
        signals.add(new SignalInfo("image_request_completed", Dictionary.class));
        return signals;
    }

It should work as a drop in replacement for single images. I haven't implemented multiple selection because my app does not require it.

Lamelynx commented 1 year ago

Thanks for sharing @blurrred :-)

Ayomideabdulazeez commented 11 months ago

I'm looking into implentering Photo picker , it might fix the problem.

Hello have you been able to implement it ?

Lamelynx commented 11 months ago

Unfortunately, I haven't taken the time for that yet.

Ayomideabdulazeez commented 11 months ago

Unfortunately, I haven't taken the time for that yet.

Okay, but would i be able to implement it myself into your plugin, i think it's the GodotGetImage.kt i need to alter right ?

Ayomideabdulazeez commented 11 months ago

So good news, i've been able to get it working with android 13, by checking the android version, and then applying the new persmissions required, so basically if the android version is 13 we use Manifest.permission.READ_MEDIA_IMAGES else we then use the Manifest.permission.READ_EXTERNAL_STORAGECapture

Ayomideabdulazeez commented 11 months ago

@Lamelynx if you want i could create a pull request ?

Lamelynx commented 11 months ago

Great work and please do a pull request. I will test it in my setup.

Ayomideabdulazeez commented 11 months ago

Great work and please do a pull request. I will test it in my setup.

Sure, I'll do that in my free-time

Ayomideabdulazeez commented 11 months ago

No problem. I forgot there was another class that I had to make in order to get it to work.

I just called it 'PhotoPicker.java' and put it in the same folder as the Godot plugin.

public class PhotoPicker extends Fragment {
  public PhotoPicker() {
      // Required empty public constructor
  }

  public static PhotoPicker newInstance() {
      PhotoPicker fragment = new PhotoPicker();
      return fragment;
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ActivityResultLauncher<PickVisualMediaRequest> pickMedia =
              registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), uri -> {
                  // Callback is invoked after the user selects a media item or closes the
                  // photo picker.
                  if (uri != null) {
                      Log.d("PhotoPicker", "Selected URI: " + uri);
                  } else {
                      Log.d("PhotoPicker", "No media selected");
                  }
              });

      pickMedia.launch(new PickVisualMediaRequest.Builder()
              .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
              .build());
  }

Can you please explain a bit how this can be implemented ?

yan88a commented 11 months ago

Hey guys any breakthroughs here with godot 4 and android 13?

Lamelynx commented 10 months ago

I have not yet successfully implement PhotoPicker but done a update based on Ayomideabdulazeez solution. I have not tested it on a Android 13 device tough.

yan88a commented 10 months ago

thanks @Lamelynx ! - did a quick check - looks like it works on my s21 (android 13) i was able to make it work via @blurrred solution as well..

yan88a commented 10 months ago

well, was happy to see the photo gallery is opened with both versions so assumed all works fine. however - couldnt retrieve the "image_request_completed" signal in both options via the "get image"/"get images"

probably some permissions issue i overlooked?

Lamelynx commented 10 months ago

Do you have android.permission.READ_MEDIA_IMAGES?

yan88a commented 10 months ago

Yep added it to the project's manifest... same result

after poking logcat for a bit - seems the signal is not fired

On Thu, Sep 28, 2023 at 7:51 PM Andreas @.***> wrote:

Do you have android.permission.READ_MEDIA_IMAGES?

— Reply to this email directly, view it on GitHub https://github.com/Lamelynx/GodotGetImagePlugin-Android/issues/15#issuecomment-1739687773, or unsubscribe https://github.com/notifications/unsubscribe-auth/AR5O6L2RR6ONOOBHTEZDPI3X4WTHNANCNFSM6AAAAAAYQ6562Q . You are receiving this because you commented.Message ID: @.***>

yan88a commented 10 months ago

Sorry for taking that long. Seems that on android 13 "onMainActivityResult" is deprecated. therefore - "image_request_completed" signal is not fired (still couldnt get it to work)

Lamelynx commented 10 months ago

We need to revise how the plugin i handling the activity then.

I have problems to implement PhotoPicker, I got class not found error even tough I implement "androidx.activity:activity-ktx:1.8.0-rc01" in the plugin. Everything is compiling but don't run on the device. Can you run this code, (I just got NoClassError for class isPhotoPickerAvailable()):

if (godot.context?.let { isPhotoPickerAvailable(it) } == true) { Log.d(TAG, "PhotoPicker is available on this device") }

yan88a commented 10 months ago

sure thing i implemented the"androidx.activity:activity:1.7.2" photo picker works ok and opens on android prior to 13 - went with @blurrred implementation.. debug'd it a bit more - and the signal is not shooting - even though "onMainActivityResult" is called. looks like the resultCode returns as "0"

still trying to figure out what that means

yan88a commented 10 months ago

@Lamelynx - same for me. couldnt find the class for - Boolean isAvilble = .isPhotoPickerAvailable(getGodot().getContext());

wired..

yan88a commented 10 months ago

@Lamelynx got it to work on android 13 and lower (11) went with @blurrred solution and changed the intent action from "get image" to "action get content) `public void getGalleryImage() { PhotoPicker PhotoPicker = new PhotoPicker(); Log.d("godot", "Call - getGalleryImage"); //Intent intent = new Intent(Intent.ACTION_PICK); Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); //activityResultLauncher.launch(intent); startActivityForResult(getActivity(), intent, 101, null);

}

@Override
public void onMainActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d("godot","result is "+ resultCode);
    if (resultCode == RESULT_OK) {
        // Get the URI of the selected media file
        Uri imageUri = data.getData();
        Bitmap bitmap;
        try {
            InputStream imageStream = getGodot().getContext().getContentResolver().openInputStream(imageUri);
            bitmap = BitmapFactory.decodeStream(imageStream);
            imageStream.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Dictionary imageDict = new Dictionary();
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream);
        try {
            stream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        imageDict.put("0", stream.toByteArray());
        Log.d("godot","fired signal");
        emitSignal("image_request_completed", imageDict);
    }
}`

painful.

bouncymarble commented 10 months ago

Hi @yan88a @Ayomideabdulazeez @blurrred , could you guys please share an .aar file that works in godot 3.5.3? I've tried to generate it myself with the solutions you provided but always get a gradle error. I'd really appreciate it, thanks.

yan88a commented 10 months ago

sure @bouncymarble aarForImage.zip

note that i only checked it with godot 4.1.1

Ayomideabdulazeez commented 10 months ago

Hi @yan88a @Ayomideabdulazeez @blurrred , could you guys please share an .aar file that works in godot 3.5.3? I've tried to generate it myself with the solutions you provided but always get a gradle error. I'd really appreciate it, thanks.

Hello, what error do you receive?

bouncymarble commented 10 months ago

Thank you @yan88a , unfortunately I was only able to export the app, had to increase Min SDK to 24 to fix a build error, but the plugin won't load while debugging.

@Ayomideabdulazeez

Hello, what error do you receive?

"Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.1.16.". I fixed that one but then, "Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.". Same error with other gradle versions, so idk what I'm doing wrong.

yan88a commented 10 months ago

@bouncymarble - try it with this gdap. note that it only has 1 function --> getGalleryImage() you should get a dic with the selected img on signal "image_request_completed" Image.zip

bouncymarble commented 10 months ago

@yan88a Thank you, it loaded and getGalleryImage() now opens the gallery, but when I pick an image it doesn't return anything. I connected the signal "image_request_completed" but it's not triggering, cmd prints this:

Call - getGalleryImage result is -1 fired signal

Btw, shouldn't you rename the plugin? maybe it's overriding the godot class with the same name "Image", and might be causing the error "Invalid call. Nonexistent function 'new' in base 'JNISingleton'", just another theory because now I get this error "Invalid call. Nonexistent function 'setOptions' in base 'JNISingleton'." which makes sense in this case. So maybe if you rename it to "GodotGetImage" it'll fix the Image.new() issue.

Is there a way to set the image parameters like we used to with setOptions()? I need to set image_height, image_width, keep_aspect, image_quality and image_format to avoid memory issues and unsupported image extensions.

yan88a commented 10 months ago

well, it wont have any abilities to set anything :) just added the getimage function (that was my needed functionality) in my case- with godot 4.1.2 it does return a dict (by the way - the intent result code is -1 --> like in your case)

as for the nonexistant function - in your case - its really not implemented in the plugin..

in mine - i do think its an issue with the gradle config, will play with it.. if by some miracle i'll manage to make it work - i'll share the aar & gdip here...

yan88a commented 10 months ago

@bouncymarble - you are a wizard. it was the name confusing it.. in any case - here is the aar & its gdap Picker.zip basically it only has 1 function and 1 signal: getGalleryImage()

image_request_completed - note that it return's a dictionary with 1 key (the pic..)

thanks man,

hope it will help you as well :)

yan88a commented 10 months ago

@bouncymarble - you managed to get an image and parse it in the editor? most images return in an array (some return as null)

bouncymarble commented 10 months ago

@yan88a I confirmed your plugin is incompatible with godot 3.5.3 because the way of connecting signals changed in godot 4. picker.connect("image_request_completed", self, "_on_image_request_completed") doesn't work, it has to be picker.image_request_completed.connect(_on_image_request_completed). I just did a test in godot 4.1.2 and it returns the dictionary as expected. So I guess I'll keep struggling with android studio. Thanks for your help anyway :)

yan88a commented 10 months ago

Ummm I think it's because I exported it with 4.1.2 templates If you want, I can export it with whatever you need later tonight Should be pretty easy..

On Fri, Oct 6, 2023, 19:26 bouncymarble @.***> wrote:

@yan88a https://github.com/yan88a I confirmed your plugin is incompatible with godot 3.5.3 because the way of connecting signals changed in godot 4. picker.connect("image_request_completed", self, "_on_image_request_completed") doesn't work, it has to be picker.image_request_completed.connect(_on_image_request_completed). I just did a test in godot 4.1.2 and it returns the dictionary as expected. So I guess I'll keep struggling with android studio. Thanks for your help anyway :)

— Reply to this email directly, view it on GitHub https://github.com/Lamelynx/GodotGetImagePlugin-Android/issues/15#issuecomment-1751054681, or unsubscribe https://github.com/notifications/unsubscribe-auth/AR5O6L7PS2VLBCETB46WR2TX6AWNFAVCNFSM6AAAAAAYQ6562SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONJRGA2TINRYGE . You are receiving this because you were mentioned.Message ID: @.***>

bouncymarble commented 10 months ago

@yan88a Yeah I'm trying to export it with the library "godot-lib.3.5.3.stable.release.aar", but maybe you could zip your project folder (android studio), so I can adapt it to my needs, plus I really want to learn how to export a plugin. Sorry for bothering you 😅

yan88a commented 10 months ago

Sure, no problem.

On Fri, Oct 6, 2023, 20:09 bouncymarble @.***> wrote:

@yan88a https://github.com/yan88a Yeah I'm trying to export it with the library "godot-lib.3.5.3.stable.release.aar", but maybe you could zip your project folder (android studio), so I can adapt it to my needs, plus I really want to learn how to export a plugin. Sorry for bothering you 😅

— Reply to this email directly, view it on GitHub https://github.com/Lamelynx/GodotGetImagePlugin-Android/issues/15#issuecomment-1751125461, or unsubscribe https://github.com/notifications/unsubscribe-auth/AR5O6L4YN4I3E5IYZ3PCLVDX6A3ONAVCNFSM6AAAAAAYQ6562SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONJRGEZDKNBWGE . You are receiving this because you were mentioned.Message ID: @.***>

yan88a commented 10 months ago

@bouncymarble - so - here is an exported aar with 3.5 template - aarFile.zip and the project zip - picker.zip couldnt zip it with the godot lib - place it into picker/app/libs and rename to godotLib.aar - than make sure to sync the gradle.

in any case - my masters degree in android plugins was by @finepointcgi ... here is his youtube video on that - he really did an amazing job https://youtu.be/kwf8SFfH4s8?si=SiTxpCxJisKAiGLp

now - if you managed to get the array into the editor from the plugin - let me know if you managed to convert it in the editor to a picture.. still having some difficulties with that.

and id anyone here has a lead on ios plugins creation - that would be an early Christmas for me :)

djordjije commented 10 months ago

I have been following this for a while. @yan88a congratulations on making your own! So, is there no way to get a single image from Android with a Godot 4 template currently? I am looking for the ability to get a single image from both Android and iOS with Godot 4. I don't mind making my own aar file. But would that even work? I am new to Godot and sorry if I am not phrasing it properly.

Lamelynx commented 8 months ago

This issue should have been resolved. Plugin is from now on only supported by Godot 4.2+ due to plugin architecture version 1 is deprecated.