achorein / expo-share-intent

🚀 Simple share intent in an Expo Native Module
MIT License
128 stars 13 forks source link

[iOS] ShareIntent not reset on background #14

Closed TomCorvus closed 4 months ago

TomCorvus commented 4 months ago

Describe the bug Hi 👋, I set up the library in a more complex flow. If intent is detected, a redirection is up to finalize adding files. When I set the app in the background, state in share intent hook is set to null but when I go back to the app, refresh function is called and ReceiveSharingIntent.getReceivedFiles returns files previously shared. So it redirects me again. It seems that ReceiveSharingIntent.clearReceivedFiles()does nothing on iOS and when I check Swift function, it is just a print of a string contrary to clearFileNames function for Android.

node_modules/react-native-receive-sharing-intent/ios/ReceiveSharingIntent.swift L162

    @objc
    func clearFileNames(){
        print("clearFileNames");
    }

node_modules/react-native-receive-sharing-intent/android/src/main/java/com/reactnativereceivesharingintent/ReceiveSharingIntentModule.java L53

  @ReactMethod
  public void clearFileNames(){
    Activity mActivity = getCurrentActivity();
    if(mActivity == null) { return; }
    Intent intent = mActivity.getIntent();
    receiveSharingIntentHelper.clearFileNames(intent);
  }

To Reproduce https://github.com/achorein/expo-share-intent-demo But on share intent demo, there is another issue on iOS that after changing app state and go back to the app, ReceiveSharingIntent.getReceivedFiles promise is not kept. Just log something in handler and nothing will appears contrary to Android which logs useShareIntent[data] no share intent detected

Environment

System:
  OS: macOS 14.2.1
  CPU: (8) x64 Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
  Memory: 80.11 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 20.9.0
    path: /usr/local/bin/node
  Yarn:
    version: 1.22.21
    path: /usr/local/bin/yarn
  npm:
    version: 10.1.0
    path: /usr/local/bin/npm
  Watchman:
    version: 2024.01.22.00
    path: /usr/local/bin/watchman
Managers:
  CocoaPods:
    version: 1.15.2
    path: /Users/thomascorbin/.rvm/gems/ruby-3.3.0/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.2
      - iOS 17.2
      - macOS 14.2
      - tvOS 17.2
      - visionOS 1.0
      - watchOS 10.2
  Android SDK:
    API Levels:
      - "23"
      - "26"
      - "28"
      - "29"
      - "30"
      - "31"
      - "33"
      - "34"
    Build Tools:
      - 28.0.3
      - 29.0.2
      - 29.0.3
      - 30.0.2
      - 30.0.3
      - 31.0.0
      - 33.0.0
      - 33.0.1
      - 34.0.0
    System Images:
      - android-26 | Google APIs Intel x86 Atom
      - android-27 | Google APIs Intel x86 Atom
      - android-27 | Google Play Intel x86 Atom
      - android-28 | Google APIs Intel x86 Atom
      - android-29 | Google APIs Intel x86 Atom
      - android-30 | Google APIs Intel x86 Atom
      - android-30 | Google Play Intel x86 Atom
      - android-31 | Google APIs ARM 64 v8a
      - android-31 | Google APIs Intel x86_64 Atom
      - android-33 | Google APIs Intel x86_64 Atom
    Android NDK: Not Found
IDEs:
  Android Studio: 2023.2 AI-232.10227.8.2321.11479570
  Xcode:
    version: 15.2/15C500b
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 3.3.0
    path: /Users/thomascorbin/.rvm/rubies/ruby-3.3.0/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.73.2
    wanted: 0.73.2
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Additional context This problem occurs on managed or bare workflow.

I know, I'm talking about react-native-receive-sharing-intent but I took as base code the share intent demo hook. I tried useShareIntent in expo-share-intent, but it does not work properly on iOS. The listener doesn't fire when the app is closed, only when the app is already opened and a file is shared in it. It looks like https://github.com/achorein/expo-share-intent/issues/11

achorein commented 4 months ago

Thanks for your deep diving, indeed react-native-receive-sharing-intent is not used anymore and the clearFileNames has no use in the new package (we are using expo event instead of storing value into native code).

I think your problem is about react-navigation and the internal useUrl of the hook, i will make an example for this. maybe the same in #11. I have to make some tests about that. (fyi, i got a production build with expo-share-intent and react-navigation without issue, app in background or not running)

TomCorvus commented 4 months ago

Great, thanks @achorein. Do we need to install react-native-receive-sharing-intent, `expo-config-plugin-ios-share-extension, and run post-install command to patch theses packages? Also set up share extension in Xcode? tbh, without documentation, I take as base code your expo share intent demo.

achorein commented 4 months ago

No you must not, please remove all demo elements : package, patches and plugins (yarn remove react-native-receive-sharing-intent expo-config-plugin-ios-share-extension). the only patch needed is the xcode patch, see new example for details example/basic

The README of share-intent-demo give the requirments

achorein commented 4 months ago

Also no need to configure anything in xcode, the goal of this package is to avoid manual configuration (do not commit ios directory, clean prebuild anytime)

TomCorvus commented 4 months ago

In my case, I need to set up manually Share extension on iOS and Android but it is fine. Thank you for your details.

TomCorvus commented 4 months ago

is there no way to avoid iOS app to return same share intent after setting app from background to active? hasShareIntent is always defined despite the call of reset share intent function. Android seems to do the thing properly.

achorein commented 4 months ago

🤔 as you say the hook auto reset intent when going to backgroud. Android and iOS works differently, ios only use deep link url to knows a new value is available (android use events). Should work on both 😅

TomCorvus commented 4 months ago

I need to verify on expo-intent basic demo. But on my iOS project, hasShareIntent is defined when I share a file, null when app is on background and defined again when I go back on it. On Android, hasShareIntent is defined, null when app is on background and always null when I go back on it.

achorein commented 4 months ago

can you share your debug log ?

 useShareIntent({ debug: true })
TomCorvus commented 4 months ago

I reproduce the issue on basic expo share intent demo.

iOS :

iOS Bundled 127ms (node_modules/expo/AppEntry.js)
 DEBUG  useShareIntent[mount] exposhareintentexample
 DEBUG  useShareIntent[mount] exposhareintentexample
 DEBUG  useShareIntent[onChange] {"value": "{ \"files\": [{\"path\":\"file:\\/\\/\\/Users\\/thomascorbin\\/Library\\/Developer\\/CoreSimulator\\/Devices\\/445B93BF-2F81-4E55-BC3E-FAD99C0D77B1\\/data\\/Containers\\/Shared\\/AppGroup\\/B83B8F48-4911-452C-ABB8-8617A991E53C\\/07542423-251D-424D-BD20-48C48F7DE973.JPG\",\"type\":0}] }"}
 DEBUG  useShareIntent[to-background] reset intent
 DEBUG  useShareIntent[active] refresh intent
 DEBUG  useShareIntent[onChange] {"value": "{ \"files\": [{\"path\":\"file:\\/\\/\\/Users\\/thomascorbin\\/Library\\/Developer\\/CoreSimulator\\/Devices\\/445B93BF-2F81-4E55-BC3E-FAD99C0D77B1\\/data\\/Containers\\/Shared\\/AppGroup\\/B83B8F48-4911-452C-ABB8-8617A991E53C\\/07542423-251D-424D-BD20-48C48F7DE973.JPG\",\"type\":0}] }"}
 DEBUG  useShareIntent[to-background] reset intent
 DEBUG  useShareIntent[active] refresh intent
 DEBUG  useShareIntent[onChange] {"value": "{ \"files\": [{\"path\":\"file:\\/\\/\\/Users\\/thomascorbin\\/Library\\/Developer\\/CoreSimulator\\/Devices\\/445B93BF-2F81-4E55-BC3E-FAD99C0D77B1\\/data\\/Containers\\/Shared\\/AppGroup\\/B83B8F48-4911-452C-ABB8-8617A991E53C\\/07542423-251D-424D-BD20-48C48F7DE973.JPG\",\"type\":0}] }"}

https://github.com/achorein/expo-share-intent/assets/3451011/92846531-b47d-4c8b-9cef-becd0e1abe6d

Android:

Android Bundled 76ms (node_modules/expo/AppEntry.js)
 DEBUG  useShareIntent[mount] exposhareintentexample
 DEBUG  useShareIntent[active] refresh intent
 DEBUG  useShareIntent[onChange] {"value": [{"contentUri": "content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F33/REQUIRE_ORIGINAL/NONE/image%2Fjpeg/2079613799", "fileName": "bateau-lac-montagnes-arriere-plan_865967-5725.jpg", "filePath": "/data/user/0/expo.modules.exposhareintent.example/cache/bateau-lac-montagnes-arriere-plan_865967-5725.jpg", "mimeType": "image/jpeg"}]}
 DEBUG  useShareIntent[to-background] reset intent
 DEBUG  useShareIntent[active] refresh intent

https://github.com/achorein/expo-share-intent/assets/3451011/f156fd7f-7d02-471f-9d5f-006d0c0f9010

As you can see, on iOS, if I reset manually or set app in background and go back on it, hook returns always the share intent. On Android, reset share intent function cleans properly the intent, and the hook does not return the intent after changing app state to active.

achorein commented 4 months ago

ok, i reproduced the issue.

It seems that the NativeEventEmitter is triggered twice (on original shareintent, and when the app become active).

The useUrl value from expo-linking is persistante when coming back from background, which retrigger the useEffect with getShareIntent from native module...

I need to understand why this behaviour happen.

achorein commented 4 months ago

fixed in v1.0.2