plus_plugins icon indicating copy to clipboard operation
plus_plugins copied to clipboard

[Bug]: Passing Context to sharePositionOrigin for iPad, no errors are thrown, but nothing happens

Open mdublin opened this issue 6 months ago • 12 comments

Platform

iOS 16.1, iPad Pro 6th Generation

Plugin

share_plus

Version

7.2.1

Flutter SDK

3.16.3

Steps to reproduce

Trying to implement share_plus on our project, and on iPad we were seeing the following error when our share button was touched:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, sharePositionOrigin: argument must be set, {{0, 0}, {0, 0}} must be non-zero and within coordinate space of source view: {{0, 0}, {1024, 1366}}, null, null)
#0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:651:7)
#1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:322:18)
<asynchronous suspension>
#2      MethodChannelShare.shareFilesWithResult (package:share_plus_platform_interface/method_channel/method_channel_share.dart:140:9)
<asynchronous suspension>

We researched the issue and added the sharePositionOrigin parameter and are passing it the box!.localToGlobal(Offset.zero) & box.size value. We are attempting to use the recommended sharePositionOrigin parameter as described here.

However, that doesn't seem to work, and now just nothing happens. There is no exception or error message, we just see in the log where the screenshot gets created and then....nothing.

Code Sample



// this is captureWidget

  Future<Uint8List> captureWidget() async {
    if (XFileList.isNotEmpty) {
      XFileList = [];
    }

    final RenderRepaintBoundary boundary =
        _globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;

    final ui.Image image = await boundary.toImage(pixelRatio: 1.0);

    final ByteData byteData =
        await image.toByteData(format: ui.ImageByteFormat.png) as ByteData;

    final Uint8List pngBytes = byteData.buffer.asUint8List();

    var appDocDir = await getTemporaryDirectory();

    print(appDocDir);

    var aphorismFileDirector =
        appDocDir.path + '/file_name${DateTime.now()}.png';

    File(aphorismFileDirector).writeAsBytes(pngBytes);

    //XFile xFile = XFile.fromData(pngBytes);
    //XFileList.add(xFile);

    XFileList.add(XFile(aphorismFileDirector));

    return pngBytes;
  }


// share btn
IconButton(
                  color: Colors.black,
                  iconSize: 16.sp,
                  icon: Icon(Icons.share, size: 16.sp),
                  onPressed: () {

                    final RenderRepaintBoundary box = _globalKey.currentContext!
                        .findRenderObject() as RenderRepaintBoundary;

                    captureWidget().then((value) => Share.shareXFiles(
                          XFileList,
                          subject: 'Good Thing',
                          text: 'https://www.something.com/',
                          sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
                        ));
                  }),

Logs

[ +730 ms] The Flutter DevTools debugger and profiler on iPad Pro (12.9-inch) (6th generation) is
available at:
                    http://127.0.0.1:9101?uri=http://127.0.0.1:61129/80dqbGmW2qk=/
[+5732 ms] flutter: Directory:
'/Users/md/Library/Developer/CoreSimulator/Devices/BCA2E004-B90B-4C81-9381-CA6A7139CDF1/data/Containers/
Data/Application/1EE6FDEE-1182-4BD7-B7AD-A52D2436ED48/Library/Caches'

Flutter Doctor

[✓] Flutter (Channel stable, 3.16.3, on macOS 13.5.2 22G91 darwin-x64, locale en-US)
    • Flutter version 3.16.3 on channel stable at /Library/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b0366e0a3f (7 days ago), 2023-12-05 19:46:39 -0800
    • Engine revision 54a7145303
    • Dart version 3.2.3
    • DevTools version 2.28.4

[!] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /Users/md/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 14.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14B47b
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.85.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.78.0

[✓] Connected device (3 available)
    • iPad Pro (12.9-inch) (6th generation) (mobile) • BCA2E004-B90B-4C81-9381-CA6A7139CDF1 • ios
      • com.apple.CoreSimulator.SimRuntime.iOS-16-1 (simulator)
    • macOS (desktop)                                • macos                                • darwin-x64
      • macOS 13.5.2 22G91 darwin-x64
    • Chrome (web)                                   • chrome                               •
      web-javascript • Google Chrome 120.0.6099.71

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 1 category.

Checklist before submitting a bug

  • [X] I searched issues in this repository and couldn't find such bug/problem
  • [X] I Google'd a solution and I couldn't find it
  • [X] I searched on StackOverflow for a solution and I couldn't find it
  • [X] I read the README.md file of the plugin
  • [X] I'm using the latest version of the plugin
  • [X] All dependencies are up to date with flutter pub upgrade
  • [X] I did a flutter clean
  • [X] I tried running the example project

mdublin avatar Dec 13 '23 06:12 mdublin

Can you reproduce the same issue in the example app and share the code with reproducer? I have assumptions that it might be something related to the context you provide.

vbuberen avatar Dec 13 '23 08:12 vbuberen

@vbuberen I have not tried that yet, it wouldn't be trivial to recreate what we're doing with the example app unfortunately. But I can confirm that the values from the context we're passing to sharePositionOrigin are:

Offset = 0.0, 0.0. Size= 1024.0, 1366.0

The above values are what I get when inspecting box.localToGlobal(Offset.zero) and box.size from:

final RenderRepaintBoundary box = _globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;

Also, I updated my code sample and included the code for the captureWidget code if that helps.

mdublin avatar Dec 13 '23 15:12 mdublin

I am experiencing the same issue.

I debugged the view in Xcode and it seems the SHSheetSceneViewController UIView has a width and height set to 0 for iPads, whereas on an iPhone 15 Pro, it shows the width and height set respectively to 393 and 852

iPad IPhone 15 Pro

marcotta avatar Jan 22 '24 15:01 marcotta

One way to fix this problem is to set the popoverPresentationController.sourceRect to a size smaller than the holding controller:

Example: in FPPSharePlusPlugin:405

if (!CGRectIsEmpty(origin)) {
    activityViewController.popoverPresentationController.sourceRect = origin;
    // See below the line I added 
    activityViewController.popoverPresentationController.sourceRect = CGRectMake(controller.view.bounds.size.width / 2.0, controller.view.bounds.size.height - 50, 1.0, 1.0);
  }

This change starts showing the popOverViewController

It means that playing around with the origin value should be able to work

UPDATE:

Setting sharePositionOrigin to:

final box = context.findRenderObject() as RenderBox?;
final sharePositionOrigin = Rect.fromLTWH(box.size.width / 2, box.size.height - 50, 1, 1);

allows showing a popOverController pointing to the center and 50 points to the bottom of the screen.

marcotta avatar Jan 22 '24 16:01 marcotta

The same issue occurs.

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] 
Unhandled Exception: PlatformException(error, sharePositionOrigin: argument must be set, {{0, 0}, {1194, 834}} must be non-zero and within coordinate space of source view: {{0, 0}, {6, 0}}, null, null)

As shown in the error above, the height of the source view is set to 0.

xncbf avatar Feb 05 '24 13:02 xncbf

One strange thing is that if you press the Share button and rotate the simulator horizontally or vertically while an error occurs, the normal action is executed.

https://github.com/fluttercommunity/plus_plugins/assets/9462045/ae200f2f-daad-42d8-a6e2-0abd8241b5d0

xncbf avatar Feb 05 '24 14:02 xncbf

Experiencing the same problem, trying to share a log file on an iPad: initially nothing happens when calling Share.shareXFiles(). Changing orientation right after suddenly does pop up the share dialog.

Method I'm using:

Future _shareFile(BuildContext context, String path, String body) async {
    final box = context.findRenderObject() as RenderBox?;
    await Share.shareXFiles(
      [XFile(path)],
      text: body,
      sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
    );
 }
XCode output as image image
XCode output as text (wall) Failed to request default share mode for fileURL:file:///var/mobile/Containers/Data/Application/AC4F9CC2-3681-4E3D-834B-223DB08DB2BE/Documents/hotos_continuous_log.txt error:Error Domain=NSOSStatusErrorDomain Code=-10814 "(null)" UserInfo={_LSLine=1608, _LSFunction=runEvaluator} Only support loading options for CKShare and SWY types. [ERROR] failed to get service endpoint creating for for item at URL file:///var/mobile/Containers/Data/Application/AC4F9CC2-3681-4E3D-834B-223DB08DB2BE/Documents/hotos_continuous_log.txt: Error Domain=NSCocoaErrorDomain Code=3328 "The requested operation couldn’t be completed because the feature is not supported." Collaboration: error loading metadata for documentURL:file:///var/mobile/Containers/Data/Application/AC4F9CC2-3681-4E3D-834B-223DB08DB2BE/Documents/hotos_continuous_log.txt error:Error Domain=NSCocoaErrorDomain Code=3328 "The requested operation couldn’t be completed because the feature is not supported." Error acquiring assertion: (501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.} Received port for identifier response: with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Gesture: System gesture gate timed out.

EDIT:

It seems in my case the sharePositionOrigin from the share_plus plugin readme doesn't work and throws the following exception:

PlatformException(error, sharePositionOrigin: argument must be set, {{0, 0}, {1573.3333333333333, 820}} must be non-zero and within coordinate space of source view: {{0, 0}, {1180, 820}}, null, null)
#0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:651:7)
#1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:334:18)
<asynchronous suspension>
#2      MethodChannelShare.shareFilesWithResult (package:share_plus_platform_interface/method_channel/method_channel_share.dart:140:9)
<asynchronous suspension>
#3      _InfoDialogState._shareFile (package:hotos/ui/widgets/dialogs.dart:310:5)
<asynchronous suspension>

Changing the sharePositionOrigin to the following works:

Future _shareFile(BuildContext context, String path, String body) async {
  final size = MediaQuery.of(context).size;
  await Share.shareXFiles(
    [XFile(path)],
    text: body,
    sharePositionOrigin: Rect.fromPoints(
      Offset.zero,
      Offset(size.width / 3 * 2, size.height),
    ),
  );
}

kazume avatar Mar 08 '24 07:03 kazume

@kazume this at least solves the problem of the error and it not appearing at all on iPad, just need to tweak it to get it to show up in the right spot/be the right size. Wish they could just fix this though.

mdublin avatar Mar 11 '24 21:03 mdublin

I mean, you are supposed to provide a valid sharePositionOrigin, that's something the plugin cannot do for you.

miquelbeltran avatar Mar 12 '24 07:03 miquelbeltran

I mean, you are supposed to provide a valid sharePositionOrigin, that's something the plugin cannot do for you.

Fair enough, it's just that the example as posted on the readme page of the plugin doesn't work for me :P That's a bit tricky, since you don't expect the error to be in code posted on the readme site of the plugin :) Not having a go, just pointing out :)

kazume avatar Mar 12 '24 07:03 kazume

Yep, it is fairly complicated. I think there is room for improvement in the plugin documentation.

The example works because it takes the context of a Builder wrapping the button, so the render box points to the right place.

As you can see, there is a Builder wrapping the share button: https://github.com/fluttercommunity/plus_plugins/blob/main/packages/share_plus/share_plus/example/lib/main.dart#L146

I could imagine many users are simply copying that section but ignoring where this context comes from, and using the top widget context, which won't work as expected.

miquelbeltran avatar Mar 12 '24 08:03 miquelbeltran

Ye, totally. I missed that one as well. I just implemented sharing a log file, so a typical "I'll put that in real quick, while already moving on the the next "real" issue in mind" thing. It's a textbook example of what we like to call the shortest computer joke: "let's do that real quick".

kazume avatar Mar 12 '24 11:03 kazume