react-native-mapbox-gl icon indicating copy to clipboard operation
react-native-mapbox-gl copied to clipboard

JS required image not working with ImageSource in release mode

Open beisert1 opened this issue 6 years ago • 17 comments

I am getting a blank white screen when loading a map running from a signed APK build on Android. I only see the mapbox info icon.

It works fine on debug for Android on all my devices, it also works if I set debuggable to true in the gradle file but obviously I am not able to send a debuggable build to google play store.

Works fine on release build for iOS. I am also not seeing any errors or anything in the logcat when I debug.

Any help would be greatly appreciated.

beisert1 avatar Jun 13 '18 15:06 beisert1

how are you generating your APK? Can you post your app/build.gradle?

nitaliano avatar Jun 13 '18 17:06 nitaliano

@nitaliano I followed the documentation here to generate the APK. https://facebook.github.io/react-native/docs/signed-apk-android.html#content

Here is the app/build.gradle

apply plugin: "com.android.application"

import com.android.build.OutputFile

project.ext.react = [
    entryFile: "index.js"
]

apply from: "../../node_modules/react-native/react.gradle"

def enableSeparateBuildPerCPUArchitecture = false

def enableProguardInReleaseBuilds = false

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.imts18"
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
            def versionCodes = ["armeabi-v7a":1, "x86":2]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }
        }
    }
}

dependencies {
    compile project(':react-native-fs')
    compile project(':react-native-splash-screen')
    compile project(':react-native-fast-image')
    compile project(':react-native-linear-gradient')
    compile fileTree(dir: "libs", include: ["*.jar"])
    compile project(':mapbox-react-native-mapbox-gl')
    compile project(':react-native-sqlite-storage')
    compile "com.android.support:appcompat-v7:26.0.1"
    compile "com.facebook.react:react-native:+"  // From node_modules
}

task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

beisert1 avatar Jun 13 '18 17:06 beisert1

@beisert1 don't ship your app like this if this works, but can you remove proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" under buildTypes.release I'm wondering if some classes could be getting stripped from the proguard config.

nitaliano avatar Jun 13 '18 18:06 nitaliano

@nitaliano same issue after removing

beisert1 avatar Jun 13 '18 18:06 beisert1

Could it be in the settings.gradle? I remember I had to remove a duplicate include for mapbox. The one I removed was prefixed with an @ symbol.

rootProject.name = 'TEST18'
include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
include ':react-native-splash-screen'
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
include ':react-native-sqlite-storage'
project(':react-native-sqlite-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlite-storage/src/android')

include ':app'
include ':mapbox-react-native-mapbox-gl'
project(':mapbox-react-native-mapbox-gl').projectDir = new File(rootProject.projectDir, '../node_modules/@mapbox/react-native-mapbox-gl/android/rctmgl')

beisert1 avatar Jun 13 '18 18:06 beisert1

@nitaliano Running react-native link marks @mapbox/react-native-mapbox-gl as unlinked for android.

rnpm-install info Platform 'ios' module @mapbox/react-native-mapbox-gl is already linked
rnpm-install info Linking @mapbox/react-native-mapbox-gl android dependency
rnpm-install info Platform 'android' module @mapbox/react-native-mapbox-gl has been successfully linked
rnpm-install info Platform 'ios' module react-native-fast-image is already linked
rnpm-install info Platform 'android' module react-native-fast-image is already linked
rnpm-install info Platform 'ios' module react-native-fs is already linked
rnpm-install info Platform 'android' module react-native-fs is already linked
rnpm-install info Platform 'ios' module react-native-linear-gradient is already linked
rnpm-install info Platform 'android' module react-native-linear-gradient is already linked
rnpm-install info Platform 'ios' module react-native-splash-screen is already linked
rnpm-install info Platform 'android' module react-native-splash-screen is already linked
rnpm-install info Platform 'ios' module react-native-sqlite-storage is already linked

But once it links, it adds @mapbox/react-native-mapbox-gl in the app/build.gradle and the settings.gradle file, however, when I do so I get an error for missing dependency

Error:Unable to find module with Gradle path ':@mapbox/react-native-mapbox-gl' (needed by module 'app'.)

beisert1 avatar Jun 14 '18 13:06 beisert1

react native link is a disaster it only works for simple use cases not when the repo has heavy native deps like this one. Look at how the example app is setup

nitaliano avatar Jun 14 '18 20:06 nitaliano

@nitaliano Figured out my issue was caused by using using an ImageSource layer and having the image url dynamic by using a prop. The only way I could get this to work in release was by using an image from our server but we need this to be offline.

            <Mapbox.ImageSource id="imageSource" url={images[`hall${this.props.navigation.state.params.hallID}`]} coordinates={coords}>
              <Mapbox.RasterLayer id="imageLayer" />
            </Mapbox.ImageSource>

beisert1 avatar Jun 15 '18 19:06 beisert1

@beisert1 dynamic urls are not supported in the native SDKS

try something like this

renderImageSource() {
   if (!this.state.url) {
      return null;
   }
   return (
     <Mapbox.ImageSource id="imageSource" url={this.state.url} coordinates={coords}>
       <Mapbox.RasterLayer id="imageLayer" />
     </Mapbox.ImageSource>
   )
}

nitaliano avatar Jun 15 '18 19:06 nitaliano

Thank you @nitaliano , unfortunately that did not work in the release build but it did work in debug mode.

Is there a proper way to hardcode a local image? I could only get this to work in release build by using a url from our server.

beisert1 avatar Jun 15 '18 19:06 beisert1

can you show me what your url looks like? is it an image that gets required in the javascript?

nitaliano avatar Jun 15 '18 19:06 nitaliano

@nitaliano The following works in release mode, an image from our server. I can't give exact location for confidential reasons.

            <Mapbox.ImageSource id="imageSource" url="https://webserver.com/image.png" coordinates={coords}>
              <Mapbox.RasterLayer id="imageLayer" />
            </Mapbox.ImageSource>

The following works on iOS release mode and android debug mode but not in android release mode

  renderImageSource() {
    if (!this.state.url) {
      return null
    }
    return (
      <Mapbox.ImageSource id="imageSource" url={this.state.url} coordinates={coords}>
        <Mapbox.RasterLayer id="imageLayer" />
      </Mapbox.ImageSource>
    )
  }

or

            <Mapbox.ImageSource id="imageSource" url={images[`hall${this.props.navigation.state.params.hallID}`]} coordinates={coords}>
              <Mapbox.RasterLayer id="imageLayer" />
            </Mapbox.ImageSource>

or

        <Mapbox.ImageSource id="imageSource" url="../assets/halls/hall.png" coordinates={coords}>
          <Mapbox.RasterLayer id="imageLayer" />
        </Mapbox.ImageSource>

or

            <Mapbox.ImageSource id="imageSource" url={images.hall} coordinates={coords}>
              <Mapbox.RasterLayer id="imageLayer" />
            </Mapbox.ImageSource>

beisert1 avatar Jun 15 '18 19:06 beisert1

we have an images file that references all the local project images.

import images from "../themes/images"

inside the images.js:

hall: require("../assets/halls/hall.png"),

We use this practice in all parts of our app and it works except in Android release build using Mapbox.imageSource

beisert1 avatar Jun 15 '18 19:06 beisert1

It works with the packager because with the packager the url will be making an http request, when you put React Native into release mode the packager is taken out of the loop here, so the ImageSource will be looking for a path on the native file system.

For now try react-native-fs to help you get the native path to the file or give this a try https://github.com/mapbox/react-native-mapbox-gl/blob/master/javascript/utils/index.js#L83 when you import an image with javascript that is turned into a number, when you pass that into resolveAssestSource that react native provides it will return an object that will contain the path to the file, try putting that path as the url.

This is something we can do internally in the SDK in the future

nitaliano avatar Jun 15 '18 20:06 nitaliano

@nitaliano I was not able to get the resolveAssetSource method to work in release mode, however, I was able to get this to work with react-native-fs.

I placed the images in the android/app/src/main/assets folder and used the RNFS.copyFileAssets function to copy those images in the RNFS.DocumentDirectoryPath. Then in the Mapbox.ImageSource I used the file://RNFS.DocumentDirectoryPath to load the image successfully in the release build.

beisert1 avatar Jun 18 '18 14:06 beisert1

Any news on this? If you use an image with require(...) for MapboxGL.ImageSource it still throws an error if the url is not a remote URL (https://...) or loaded from the local filesystem (file://...). It should be possible to load images provided with the app bundle with require. Having to use a remote file or a file stored to the local filesystem is not an option in many cases. As long as you're in debug mode and connected to the local packager it can resolve the URL but in release mode or when you're disconnected from the packager it still throws an error. Any help appreciated

janweigel avatar Sep 03 '20 04:09 janweigel

I am having the same issue. I am using Expo so adding an image in Android folder will not work in my case. @nitaliano

kuldip-simform avatar Sep 27 '23 11:09 kuldip-simform