Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sharePic function not working on Godot 3.0.2 and Android #1

Closed
samuelpedrajas opened this issue May 6, 2018 · 10 comments
Closed

sharePic function not working on Godot 3.0.2 and Android #1

samuelpedrajas opened this issue May 6, 2018 · 10 comments
Assignees

Comments

@samuelpedrajas
Copy link

samuelpedrajas commented May 6, 2018

Since currently there are issues with screen capture in Godot 3, I have modified the demo project a little bit to try this:

func _on_share_btn_pressed():
	# if share was found, use it
	if share != null:
		share.sharePic("res://icon.png", "Image Sharing", "Sharing image with GodotShare", "It's a demo app for testing GodotShare. Do you like it?")

The sharing menu is showing correctly and the title, subject and text are set correctly as well. However, the picture is not attached in any case (Facebook, Whatsapp, Gmail...) and instead an empty box is shown. No errors are shown in the console.

Am I doing something wrong? I have tried this on Godot 3.0.2 and Xiaomi MI5 with Android MIUI.

Thanks

@Shin-NiL
Copy link
Owner

Shin-NiL commented May 7, 2018

The module expects a native absolute path, so you'll need to convert your res:// reference, try something like:

var absolute_path = ProjectSettings.globalize_path("res://icon.png")

Please tell me if it works, I've not tested ;)

@Shin-NiL Shin-NiL self-assigned this May 7, 2018
@samuelpedrajas
Copy link
Author

I have tried this:

func _on_share_btn_pressed():
	# if share was found, use it
	if share != null:
		var img_path = ProjectSettings.globalize_path("res://icon.png")
		print(img_path)
		share.sharePic(img_path, "Image Sharing", "Sharing image with GodotShare", "It's a demo app for testing GodotShare. Do you like it?")

It doesn't work and it just prints "icon.png".

I also tried this:

func _on_share_btn_pressed():
	# if share was found, use it
	if share != null:
		var img = Image.new()
		var img_load = "res://icon.png"
		var img_save = OS.get_user_data_dir() + "/icon.png"

		print("PATH: ", img_save)
		print("LOAD: ", img.load(img_load))
		print("SAVE: ", img.save_png(img_save))

		share.sharePic(img_save, "Image Sharing", "Sharing image with GodotShare", "It's a demo app for testing GodotShare. Do you like it?")

which prints this:

PATH: /data/data/org.godotengine.godotsharedemo/files/icon.png
LOAD: 0
SAVE: 0

0 means OK but it doesn't work neither. With that code the print messages are shown after closing the sharing menu, when coming back to the game. But if I add one "yield(get_tree(), "idle_frame")" right after the last print, I get the output in the console just when I tap the button, before opening the sharing menu.

I also have tried to find a directory called "org.godotengine.godotsharedemo" in my Android device but it doesn't seem to exist. I'm not sure if this is related to the issue.

I'm not very experienced so I'm just trying things. Any guidance or tips for a workaround would be very appreciated.

Thanks for your work!

@Shin-NiL
Copy link
Owner

Shin-NiL commented May 7, 2018

Well, I think we found some new bugs...

  1. I can confirm that ProjectSettings.globalize_path isn't working on Android, it's working fine on PC.
  2. I've tried this:
	var texture = load("res://icon.png")
	var img = texture.get_data()

but the get_data() is returning null, once again it's working as expected on PC.

It seems like all the problem is because the save isn't working as it should also. Can you test your code on PC to see if the file is saved? You can use the following code to check this out:

	var file = File.new()
	print(file.file_exists(image_save_path))

or just open the directory using your file manager.

@samuelpedrajas
Copy link
Author

I've tried this code:

func _on_share_btn_pressed():
	var img = Image.new()
	var img_load = "res://icon.png"
	var img_save = OS.get_user_data_dir() + "/icon.png"

	print("PATH: ", img_save)
	print("LOAD: ", img.load(img_load))
	print("SAVE: ", img.save_png(img_save))

	# check if it exists
	var file = File.new()
	print(file.file_exists(img_save))

For both Android and PC I get True in the last print. I can also see the image (icon.png) in my .local/share/godot/app_userdata/GodotShare Demo folder in my file manager, so it gets saved properly. However if I look for icon.png in my Android's file manager, I get no results.

I get null on get_data() as well.

@samuelpedrajas
Copy link
Author

samuelpedrajas commented May 8, 2018

After hours of research I managed to make it work 😀. I read this section https://developer.android.com/training/secure-file-sharing/ and they recommend to use a FileProvider rather than the Uri.fromFile method to get the URI of the file. These are the steps I followed:

  1. Update the AndroidManifest.xml inside the platform/android/java folder by inserting the following bit of XML between the <application>...</application> tags:
      <provider
          android:name="android.support.v4.content.FileProvider"
          android:grantUriPermissions="true"
          android:exported="false"
          android:authorities="${applicationId}">

          <meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/file_provider_paths"/>

      </provider>
  1. Create a new XML file platform/android/java/res/xml/file_provider_paths.xml (probably you will have to create the xml folder) with the following content:
<paths>
    <files-path path="." name="share" />
</paths>
  1. Rewrite the sharePic method in the GodotShare.java like this:
...
import android.support.v4.content.FileProvider;
...
	public void sharePic(String image, String title, String subject, String text)
	{
		File f = new File(image);
		Uri uri = FileProvider.getUriForFile(activity, activity.getPackageName(), f);

		Intent shareIntent = new Intent(Intent.ACTION_SEND);
		shareIntent.setType("image/*");
		shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
		shareIntent.putExtra(Intent.EXTRA_TEXT, text);
		shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
		shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
		activity.startActivity(Intent.createChooser(shareIntent, title));

		Log.d("godot", "sharePic");
	}
  1. Run gradlew build and make sure you use these new templates.
  2. Load the Godot 3 demo in this repository and rewrite the _on_share_btn_pressed method like this:
func _on_share_btn_pressed():
	if share != null:
		var img = Image.new()
		var img_load = "res://icon.png"
		var img_save = OS.get_user_data_dir() + "/icon.png"

		print("PATH: ", img_save)
		print("LOAD: ", img.load(img_load))
		print("SAVE: ", img.save_png(img_save))

		yield(get_tree(), "idle_frame")
		share.sharePic(img_save, "Image Sharing", "Sharing image with GodotShare", "It's a demo app for testing GodotShare. Do you like it?")

That worked for me.

@Shin-NiL
Copy link
Owner

Shin-NiL commented May 8, 2018

Thank you very much, I'll read the docs and probably update the module code ;)

@samuelpedrajas
Copy link
Author

samuelpedrajas commented May 8, 2018

Today I realised that my amends only work for "icon.png" but not for the rest of PNG files due to this issue: godotengine/godot#15380. I think currently there is no way of copying PNG files during the export because Godot uses the ".import" files instead. This means that theimg.load method won't work for PNG files because they don't exist when running the game. That wouldn't be a problem if we had the ability to create Image objects from those ".import" files, but that's not the case since it looks like the get_data method is also broken on Android and iOS as you reported here: godotengine/godot#16694. I think this makes a complicated scenario to share PNG files on Android.

However, since I needed the ability to share PNG files, no screen capture needed, I've come up with a workaround. For example, if you wanted to share two pictures "res://img1.png" and "res://img2.png" in your Godot 3 demo project, you could follow these steps:

  1. Duplicate both pictures and rename the new ones to, for example, "res://img1.share" and "res://img2.share". This way they won't be recognised as PNG files so no ".import" file will be created.

  2. Go to Project > Export > Android > Resources and add *.share in "filters to export" so they get copied during the export.

  3. Modify the _on_share_btn_pressed method in the "share_btn.gd" file (remember this is the Godot 3 demo here) with the following code (you could replace "img1" with "img2" if you wanted):

func _on_share_btn_pressed():
	# if share was found, use it
	if share != null:
		var from_file = "res://img1.share"
		var to_file = "user://tmp.png"

		# copy file
		var dir = Directory.new()
		dir.copy(from_file, to_file)

		yield(get_tree(), "idle_frame")

		share.sharePic(
			OS.get_user_data_dir() + "/tmp.png",
			"Image Sharing",
			"Sharing image with GodotShare",
			"It's a demo app for testing GodotShare. Do you like it?"
		)

And that should do the trick. I am aware this is a dirty workaround with all sorts of drawbacks, but I couldn't come up with a better solution. This won't be needed when those 2 issues from the Godot repository are fixed. Let me know if I am missing something obvious or if there is some better solution to this.

I hope I explained myself well enough, let me know otherwise.

@Shin-NiL
Copy link
Owner

Shin-NiL commented May 8, 2018

Perfect explanation, my friend, it's a good workaround to me. Thanks for sharing your research, I'm sure it'll help many other users with the same issues ;)

I just updated the code to use FileProvider, your solution should work now with no changes on the module.

@samuelpedrajas
Copy link
Author

Great, I've just tested the new update and it works fine for me. Thanks!

@Shin-NiL
Copy link
Owner

The screen capture was fixed on Godot 3.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants