Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

React Native Upgrade Diary

Actionable items

  • expo-cli doesn't recognize client_log events sent by the app and prints a warning (comment)
  • Bundling progress is not shown on iOS (comment). Actually on a versioned SDK38 project it was shown, so this could be an intermittent issue.
  • Metro is not able to symbolicate stacktraces (comment). My small investigation points to rawBodyMiddleware available in @react-native-community/cli not being applied when passing request through to metro, but I don't know how to fix it.
  • An exception thrown during initialization phase of native modules causes Expo Client to crash (see fix)

History

  1. Checked out 0.62-stable branch for which the latest commit is "Bump version numbers", so we're rebasing our changes on top of 0.62.2.

  2. Created a new branch sdk-38 (here).{

  3. Opened https://github.com/expo/react-native/commits/sdk-37 which, fortunately, is able to show all our customizations on one page.

  4. Went through every commit verifying if it's worth cherry-picking onto 0.62-stable:

  5. Pushed the sdk-38 branch.

  6. Went out of the submodule and then through our workspace (so omitting templates) replacing "react": "16.9.0" with "16.11.0" and "react-native": "0.61.4" with "0.62.2", react-dom with 16.11.0 and @types/react-native with latest version there was, ^0.62.

  7. Ran yarn in our workspace. First, it failed with:

    error An unexpected error occurred: "ENOENT: no such file or directory, lstat '/Users/sjchmiela/Applications/expo/node_modules/react-native/node_modules/pretty-format/node_modules'".

    After second yarn it succeeded. This may have been a problem of me removing react-native-lab/react-native from the list of workspaces before to be able to reinstall dependencies when applying the commit removing devDependencies from react-native project.

  8. Decided to focus on iOS Expo client.

    • Installed Pods in the Expo client workspace.

    • Noticed there is a bug in our versioning script that makes versioned Reacts depend on unversioned React. Fixed manually in #8301 and informed Tomasz of the problem as the expotools owner.

    • After starting the app crashed due to EXDevSettings not overriding supportedEvents instance method, which (it looks like) is required now. Added:

      - (NSArray<NSString *> *)supportedEvents
      {
        return [super supportedEvents];
      }
    • First load of NCL timed out. I entered the logged URL of the bundle and opened it in Safari. It started to build immediately (which didn't happen before). Reloading JS after the bundle has been built successfully started the app.

    • Multiple Unrecognized event: logs have been printed in the console due to old version of expo-cli.

    • Had a problem with Roboto font loading in NCL which was happening due to yesterday's change in google/fonts repository. Great timing!

    • Decided to see if I can install Flipper in Expo Client easily. Added required Pods copying RN's Podfile scripts and removing :configuration => "Debug" so that it's available in release mode too.

      • Had a problem with Flipper's Time.h

        Typedef redefinition with different types ('uint8_t' (aka 'unsigned char') vs 'enum clockid_t')

        Fixed by lowering deployment targets as in this comment.

      • Had a problem with Swift integration

        Undefined symbol: protocol descriptor for Swift.ExpressibleByFloatLiteral flipper

        Fixed by following instructions at this issue.

      • Had a problem with instant crash after the app start

        This copy of libswiftCore.dylib requires an OS version prior to 12.2.0. (lldb)

        Fixed by following instructions provided in this SO answer.

      • Had a problem with instantiating the FlipperClient, Xcode wasn't able to resolve the symbol, decided to stop working on it for now.

    • Wojtek warned be that GL may crash on RN 0.62.2, so decided to open NCL again and see if it's true — it was not!

    • 🚨 Noticed the bundling progress isn't showing.

    • 🚨 Noticed that when error is raised it fails to be sent to the dev environment (actually it was sent, but there was another error that suggested they did not, see image below). It looks like Metro can't read body sent to /symbolicate endpoint by symbolicateStackTrace. The body is undefined and error logged in console is

      SyntaxError: Unexpected token u in JSON at position 0
          at JSON.parse (<anonymous>)
          at /Users/sjchmiela/Applications/expo/node_modules/metro/src/Server.js:1026:28
          at Generator.next (<anonymous>)
          at asyncGeneratorStep (/Users/sjchmiela/Applications/expo/node_modules/metro/src/Server.js:99:24)
          at _next (/Users/sjchmiela/Applications/expo/node_modules/metro/src/Server.js:119:9)

      I think it may be an issue in Metro (I wasn't able to find rawBody property exposed in connect where they suppose it's being added.

    • While investigating issue above I found an error in expo where we assume symbolicateStackTrace returns an array while in fact since RN 0.62 it returns an object (and the array under stack key). Fixed this by using the ?.stack value.

  9. Let's move to Android Expo Client!

    • Running et update-react-native didn't produce any problems. Good for us.
    • At first compilation failed as native delta client was removed from Android, so I had to update the ExponentDevBundleDownloadListener so it doesn't expect NativeDeltaClient as an argument to onSuccess. Then the project compiled!
    • At first it failed to run and behaved like it couldn't download Home bundle. I rebuilt the project, second time it succeeded. After cleaning the app from the device and reinstalling the problem did not occur again, it must have been an intermittent issue.
    • NCL ran ok, it even showed building progress (which wasn't the case on iOS).
    • React Native Upgrade Tool suggested we should add androidx.swiperefreshlayout:swiperefreshlayout:1.0.0 dependency, but without it our project still compiled and worked ok. This is thanks to other dependencies, namely net.openid:appauth:0.7.1 and expo-ads-admob which depend on androidx.browser:browser which includes the offending package. To ensure that we don't fail to include this package I've added it to :expoview dependencies.
    • Another suggestion was to add |uiMode to android:configChanges of the activity in AndroidManifest.xml. I have decided to add this, since it should not break anything and should prevent app recreation as per introducing PR.
    • Another AndroidManifest-related change was to add launchMode=singleTask. This already was the case for MainActivity and HomeActivity, so standalone apps already work this way. I've decided not to add it to ExperienceActivity. For more information see introducing PR.
  10. Decided to be a good citizen and see if building React Native for ejected projects works ok.

    • Lo and behold, et add-sdk --platform android --sdkVersion 38.0.0 succeeded!
    • Then, there were two problems:
      1. First had to do with FileProvider in the SDK38 Android manifest. It didn't set authorities to ${applicationId}.provider as other SDKs did. Had to change it to this value.

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true" >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
      2. Then it turned out that NetworkingModule is no longer a Java native module—now it's a TurboModule! Due to this we no longer can fetch it by getNativeModule method on ReactContext in SharedCookiesDataSourceFactory, we need to fetch it like a TurboModule, i.e. by name. After applying fetching the module by

        ((NetworkingModule) reactApplicationContext.getCatalystInstance().getNativeModule("Networking"))

        it compiled again.

      3. MainApplication failed to compile as versioned AppLoaderPackagesProviderInterface<ReactPackage> was clashing with getExpoPackages() of unversioned MainApplication. This is a known problem (at least I remember it) that singletons are neither prefixed nor deleted when adding a versioned SDK. Removing abi38_0_0.org.unimodules.apploader fixed the issue.

      4. Then the JS application couldn't start throwing the following exception

        2020-05-15 13:45:53.906 18656-18947/host.exp.exponent E/unknown:NativeModuleInitError: Failed to create NativeModule "SourceCode"
            java.lang.NoSuchMethodError: No direct method <init>(Lcom/facebook/react/bridge/ReactApplicationContext;)V in class Lcom/facebook/fbreact/specs/NativeSourceCodeSpec; or its super classes (declaration of 'com.facebook.fbreact.specs.NativeSourceCodeSpec' appears in /data/app/host.exp.exponent-2/base.apk:classes3.dex)
                at com.facebook.react.modules.debug.SourceCodeModule.<init>(SourceCodeModule.java:26)
                at com.facebook.react.CoreModulesPackage.getModule(CoreModulesPackage.java:153)
                at com.facebook.react.TurboReactPackage$ModuleHolderProvider.get(TurboReactPackage.java:159)
                at com.facebook.react.TurboReactPackage$ModuleHolderProvider.get(TurboReactPackage.java:147)
                at com.facebook.react.bridge.ModuleHolder.create(ModuleHolder.java:191)
                at com.facebook.react.bridge.ModuleHolder.getModule(ModuleHolder.java:156)
                at com.facebook.react.bridge.JavaModuleWrapper.getModule(JavaModuleWrapper.java:56)
                at com.facebook.react.bridge.JavaModuleWrapper.getConstants(JavaModuleWrapper.java:126)
                at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
                at android.os.Handler.handleCallback(Handler.java:751)
                at android.os.Handler.dispatchMessage(Handler.java:95)
                at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
                at android.os.Looper.loop(Looper.java:154)
                at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
                at java.lang.Thread.run(Thread.java:761)
        

        After a second I realized that it may be happening due to com.facebook.fbreact namespace not being versioned, so I added it to android-packages-to-rename.txt in expotools and redone et add-sdk, reapplying all the changes from points 1 to 3.

      5. Then Expo Client started. It could run unversioned experiences without problems, but an SDK38 experience could not start. The error was

        2020-05-15 15:41:03.233 26592-26702/host.exp.exponent E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
            Process: host.exp.exponent, PID: 26592
            java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libreactnativejni_abi38_0_0.so
                at com.facebook.soloader.SoLoader.doLoadLibraryBySoName(SoLoader.java:789)
                at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:639)
                at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:577)
                at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:525)
                at abi38_0_0.com.facebook.react.bridge.ReactBridge.staticInit(ReactBridge.java:34)
                at abi38_0_0.com.facebook.react.bridge.Inspector.<clinit>(Inspector.java:21)
                at abi38_0_0.com.facebook.react.bridge.Inspector.getPages(Inspector.java:28)
                at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.getPages(InspectorPackagerConnection.java:151)
                at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.handleProxyMessage(InspectorPackagerConnection.java:66)
                at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection$Connection.onMessage(InspectorPackagerConnection.java:221)
                at okhttp3.internal.ws.RealWebSocket.onReadMessage(RealWebSocket.java:323)
                at okhttp3.internal.ws.WebSocketReader.readMessageFrame(WebSocketReader.java:219)
                at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.java:105)
                at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.java:274)
                at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:214)
                at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
                at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                at java.lang.Thread.run(Thread.java:761)
        

        Decided to contact Wojtek who has proven to be helpful in these situations. Together we ensured that the offending library is in the built AAR of the library.

        Fixed by upgrading SoLoader to 0.8.2!

      6. Then the problem was that when starting an SDK38 experience, Expo Client crashed with

        E/art: Failed to register native method abi38_0_0.com.facebook.react.jscexecutor.JSCExecutor.initHybrid(Labi38_0_0/com/facebook/react/bridge/ReadableNativeMap;)Lcom/facebook/jni/HybridData; in /data/app/host.exp.exponent-1/base.apk
        E/art: ----- class 'Labi38_0_0/com/facebook/react/jscexecutor/JSCExecutor;' cl=0x12c4e790 -----
        E/art:   objectSize=188 (128 from super)
        E/art:   access=0x0000.0000
        E/art:   super='java.lang.Class<abi38_0_0.com.facebook.react.bridge.JavaScriptExecutor>' (cl=0x12c4e790)
        E/art:   vtable (1 entries, 2 in super):
        E/art:      0: java.lang.String abi38_0_0.com.facebook.react.jscexecutor.JSCExecutor.getName()
        E/art:   direct methods (3 entries):
        E/art:      0: void abi38_0_0.com.facebook.react.jscexecutor.JSCExecutor.<clinit>()
        E/art:      1: void abi38_0_0.com.facebook.react.jscexecutor.JSCExecutor.<init>(abi38_0_0.com.facebook.react.bridge.ReadableNativeMap)
        E/art:      2: abi38_0_0.com.facebook.jni.HybridData abi38_0_0.com.facebook.react.jscexecutor.JSCExecutor.initHybrid(abi38_0_0.com.facebook.react.bridge.ReadableNativeMap)
        E/log: error java.lang.NoSuchMethodError: no static or non-static method "Labi38_0_0/com/facebook/react/jscexecutor/JSCExecutor;.initHybrid(Labi38_0_0/com/facebook/react/bridge/ReadableNativeMap;)Lcom/facebook/jni/HybridData;"
        

        I have confirmed that SDK37 experiences load properly, that SDK37's JSCExecutor.java expects an abi37_0_0.….HybridData (analogous to SDK38's). After inspecting Hybrid.h file it turned out that React Native moved JNI out of the repo in favor of downloading it from a separate library in buildtime. This caused the prefixed files to be overridden with the newly downloaded ones. We had two ways out:

        1. version the outsourced fbjni library with expolib_v1

          • 👍 makes different ABIs isolated
          • 👎 very difficult to do
          • I went down that path, it wasn't pretty
            • First, I needed to version the libraries. android-versioning from tools wasn't much help, as it could only change packages of Java classes and we also needed to rename strings inside and manipulate inside the .so file

              I think that's due to this recent commit — Migrate to FBJNI — that in buildtime downloads headers and JNI. I have removed offending Gradle tasks from execution — the class names remained prefixed even after starting the build. On the other hand I'm afraid that the downloaded JNI isn't and won't be prefixed, so it'll crash later and harder, but let's see. If so, I will try reverting only that commit. If not, maybe not-versioning FBJNI may be the right way to fix?

              java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libreactnativejni_abi38_0_0.so caused by: dlopen failed: library "libglog_init_abi38_0_0.so" not found result: 0
              

              This looks like we could fix it somehow managing dependencies, since libglog_init_abi38_0_0.so is inside the reactandroid-abi38_0_0 AAR, so it only isn't added to the APK.

              This I have to leave for the weekend. See you Monday!


              After Wojtek's suggestion that if libglog_init_abi38_0_0.so is in the AAR it should be automatically bundled inside the APK I have decided to clean and reinstall the app on the device. As one could imagine this has solved the former issue and the error now was a bit different:

              It looks like this was some fix, the app now crashes with:

              2020-05-18 09:53:12.224 10401-10550/host.exp.exponent E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                  Process: host.exp.exponent, PID: 10401
                  java.lang.NoSuchFieldError: no type "Labi38_0_0/com/facebook/jni/HybridData$Destructor;" found and so no field "mDestructor" could be found in class "Lcom/facebook/jni/HybridData;" or its superclasses
                      at abi38_0_0.com.facebook.react.bridge.Inspector.instance(Native Method)
                      at abi38_0_0.com.facebook.react.bridge.Inspector.getPages(Inspector.java:28)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.getPages(InspectorPackagerConnection.java:151)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.handleProxyMessage(InspectorPackagerConnection.java:66)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection$Connection.onMessage(InspectorPackagerConnection.java:221)
                      at okhttp3.internal.ws.RealWebSocket.onReadMessage(RealWebSocket.java:323)
                      at okhttp3.internal.ws.WebSocketReader.readMessageFrame(WebSocketReader.java:219)
                      at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.java:105)
                      at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.java:274)
                      at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:214)
                      at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
                      at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                      at java.lang.Thread.run(Thread.java:761)
                   Caused by: java.lang.ClassNotFoundException: Didn't find class "abi38_0_0.com.facebook.jni.HybridData$Destructor" on path: DexPathList[[zip file "/data/app/host.exp.exponent-1/base.apk"],nativeLibraryDirectories=[/data/app/host.exp.exponent-1/lib/arm, /data/app/host.exp.exponent-1/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
                      at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                      at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
                      at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                      at abi38_0_0.com.facebook.react.bridge.Inspector.instance(Native Method) 
                      at abi38_0_0.com.facebook.react.bridge.Inspector.getPages(Inspector.java:28) 
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.getPages(InspectorPackagerConnection.java:151) 
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.handleProxyMessage(InspectorPackagerConnection.java:66) 
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection$Connection.onMessage(InspectorPackagerConnection.java:221) 
                      at okhttp3.internal.ws.RealWebSocket.onReadMessage(RealWebSocket.java:323) 
                      at okhttp3.internal.ws.WebSocketReader.readMessageFrame(WebSocketReader.java:219) 
                      at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.java:105) 
                      at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.java:274) 
                      at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:214) 
                      at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206) 
                      at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
                      at java.lang.Thread.run(Thread.java:761)
              

              A reasonable error, given there really is no abi38_0_0.….HybridData — it has been extracted to com.facebook.fbjni:fbjni-java-only library. Let's version it with expolib_v1 (😭) and see if this lets us move further.

              Did version it with expolib_v1 after a couple of fixes in tools/android-versioning, got another error:

              E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                  Process: host.exp.exponent, PID: 13294
                  java.lang.NoSuchFieldError: no "Labi38_0_0/com/facebook/jni/HybridData$Destructor;" field "mDestructor" in class "Lcom/facebook/jni/HybridData;" or its superclasses
                      at abi38_0_0.com.facebook.react.bridge.Inspector.instance(Native Method)
                      at abi38_0_0.com.facebook.react.bridge.Inspector.getPages(Inspector.java:28)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.getPages(InspectorPackagerConnection.java:151)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection.handleProxyMessage(InspectorPackagerConnection.java:66)
                      at abi38_0_0.com.facebook.react.devsupport.InspectorPackagerConnection$Connection.onMessage(InspectorPackagerConnection.java:221)
                      at okhttp3.internal.ws.RealWebSocket.onReadMessage(RealWebSocket.java:323)
                      at okhttp3.internal.ws.WebSocketReader.readMessageFrame(WebSocketReader.java:219)
                      at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.java:105)
                      at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.java:274)
                      at okhttp3.internal.ws.RealWebSocket$2.onResponse(RealWebSocket.java:214)
                      at okhttp3.RealCall$AsyncCall.execute(RealCall.java:206)
                      at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
                      at java.lang.Thread.run(Thread.java:761)
              

              I guess something somewhere still uses unversioned HybridData for some reason.

            • Then I decided to clone fbjni and version it manually. This however didn't go well, so I decided to try the other approach.

              Decided to clone fbjni from https://github.com/facebookincubator/fbjni, rename all the com.facebook. to expolib_v1.com.facebook. and this way have multiple versions of fbjni in one application. Unfortunately even after numerous tries I have failed to compile the application. After discussing with Wojtek I have decided not to try to version fbjni. Let's use only one copy of this library for all our ABIs! Thanks to fbjni being an OSS project, if they introduce any breaking changes in versions used in different React Natives we shall be able to add backwards compatibility and roll our own fbjni. (In fact we already treat all other React's dependencies this way—hope for compatibility). The branch with versioned fbjni etc is @sjchmiela/reactnative-0.62-versionedfbjni.

        2. decide not to version fbjni

          • 👍 easy to do
          • 🤔 doesn't necessarily cause us problems—the source code is available at facebookincubator/fbjni, if Facebook introduces any breaking changes we could monkey-patch them and roll our own fbjni

        Checked out branch before trying to add versioned fbjni, removed com.facebook.jni from among packages that ought to be prefixed with abiXX_X_X by removing it from android-packages-to-rename.txt (noticed that fbjni is used in multiple other places in expotools/android, so I may need to remove that too.

        Fortunately, the et add-sdk command went smooth and the client compiled afterwards (after applying changes from the beginning of this point). Unversioned Home ran ok. Running an SDK38 experience however, resulted in a crash related to expo-notifications not being versioned properly (since there are many singletons and logic supposed to be shared, a couple of entries had to be added to the .txt). After updating android-packages-to-keep.txt and adding a new feature to copy-unimodule.sh that is removing unversioned files from the versioned copy, the SDK38 experience ran without problems, but this got me thinking—would an error when instantiating a native module result in a hard crash of an application? I have verified that no, it doesn't on older SDKs.

        A small investigation had proved the culprit to be the new LogBoxModule which, during initialization phase, has posted on UI thread a Runnable that was adding a root view. This threw an exception if by the time the Runnable got to run the Catalyst instance was already gone. I wrapped the offending code with try-catch and reversioned SDK38. The problem went away—throwing an exception in onCreate did not cause Expo client to hard crash.

        At this point I would say that Expo client is more or less ready to be QA-ed for any non-obvious problems.

  11. Moved to iOS Expo client and versioning.

    • This has went (not surprisingly) quite smooth. All I had to do was update expotools for jscallinvokercallinvoker change and add post transforms for a couple of files (NSData+EXFileSystem file gets versioned to ABI38_0_0NSData+EXFileSystem but the import points to NSData+ABI38_0_0EXFileSystem).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment