I have a chatService class in my app which works well when in debug mode but doesn't work at all when i release the app-release apk.
My chat component file looks like this
import React from 'react';import {connect} from 'react-redux';import { GiftedChat, Send, Bubble, Time, Composer,} from 'react-native-gifted-chat';import ChatService from '../services/chatService';const TIMEOUT = 10000;class Chatbox extends React.Component { constructor(props) { super(props); this.renderChatMessage = this.renderChatMessage.bind(this); this.renderEarlierMessages = this.renderEarlierMessages.bind(this); this.receiveChatMessage = this.receiveChatMessage.bind(this); this.loadEarlier = this.loadEarlier.bind(this); this.setChannelFailed = this.setChannelFailed.bind(this); this.chatService = ChatService( this.props.auth.token, this.props.auth.roomToken, this.receiveChatMessage, this.renderChatMessage, this.renderEarlierMessages, ); } componentWillUnmount() { this.chatService.close(); } componentDidMount() { this.chatService.open(); } setChannelFailed() { this.props.setChannelFailed(); } // renderOnlineUsers(presence) { // presence.list((id, { metas: [first, ...rest] }) => { // let count = rest.length + 1; // }); // } receiveChatMessage(messages) { const userUUID = this.props.currentUser.uuid; let reciveObj = _.map(messages, (value, key) => { return { _id: value.id, text: value.message, createdAt: value.inserted_at, user: { _id: value.user.uuid, name: value.user.name, }, }; }); const message = reciveObj[0]; if (message.user._id !== userUUID) { this.props.appendMessage(message); } } renderChatMessage(messages) { let newMessages = _.map(messages.messages, (value, key) => { return { _id: value.id, text: value.message, createdAt: value.inserted_at, user: { _id: value.user.uuid, name: value.user.name, }, }; }); if (newMessages.length > 0) { const lastMessage = newMessages[newMessages.length - 1]; if (newMessages.length < 30) { this.props.setLoadMore(false); } else { this.props.setLoadMore(true); } this.props.setMessages(newMessages); this.props.setLastMessage(lastMessage._id); } } loadEarlier() { const {lastMessageId} = this.props.socket; this.chatService.loadEarlier(lastMessageId); } renderEarlierMessages(messages) { let newMessages = _.map(messages.messages, (value, key) => { return { _id: value.id, text: value.message, createdAt: value.inserted_at, user: { _id: value.user.uuid, name: value.user.name, }, }; }); const lastMessage = newMessages[newMessages.length - 1]; if (newMessages.length < 30) { this.props.setLoadMore(false); } else { this.props.setLoadMore(true); } this.props.setEarlierMessages(newMessages); this.props.setLastMessage(lastMessage._id); } onSend(messages) { let newMessage = messages[0]; this.props.appendMessage(newMessage); GiftedChat.append(messages); this.chatService.send(messages); analytics.track('Messages Sent', { messages: messages, }); } // draw our ui render() { const userUUID = this.props.currentUser.uuid; const userName = this.props.currentUser.name; const {loadMore} = this.props.socket; const {token, roomToken} = this.props.auth; if (token === null || roomToken === null) { return (<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}><Image style={{width: 300, height: 300, resizeMode: 'contain'}} source={require('../assets/images/error.png')} /></View> ); } else { return (<KeyboardAvoidingView style={{flex: 1, paddingTop: 0}} keyboardVerticalOffset="-210" behavior="padding" enabled><GiftedChat scrollToTop loadEarlier={loadMore} isTyping={true} onLoadEarlier={this.loadEarlier} messages={this.props.messages} user={{ _id: userUUID, }} onSend={messages => { messages.forEach(element => { element.user = { _id: userUUID, name: userName, }; }); this.onSend(messages); }} maxHeight={300} renderBubble={props => { return (<Bubble {...props} textStyle={{ right: { color: '#fff', fontFamily: 'Font-Regular', }, left: { color: '#fff', fontFamily: 'Font-Regular', }, }} wrapperStyle={{ right: { backgroundColor: '#5BC388', borderTopLeftRadius: 5, borderBottomLeftRadius: 5, borderBottomRightRadius: 0, marginBottom: 5, paddingRight: 10, paddingBottom:5, minWidth: 100, }, left: { backgroundColor: '#292C35', borderTopRightRadius: 5, borderBottomRightRadius: 5, borderBottomLeftRadius: 0, marginBottom: 5, paddingLeft: 10, paddingBottom:5, minWidth: 100, }, }} /> ); }} renderLoading={() => { return (<ActivityIndicator style={{marginTop: 10, paddingTop: 50}} size="large" /> ); }} // renderComposer={props => { // return ( // <Composer // {...props} // style={{backgroundColor: '#121519'}} // placeholderTextColor="#fff" // textInputStyle={{ // backgroundColor: '#121519', // marginLeft: 0, // marginTop: 0, // height: 50, // color: '#fff', // }}> // <View style={{backgroundColor: '#121519'}} /> // </Composer> // ); // }} renderSend={props => { return (<Send {...props}><View style={{ marginRight: 0, marginBottom: 0, height: 44, width: 60, //backgroundColor: '#121519', alignItems: 'center', justifyContent: 'center', }}><Text style={{ color: '#5BC388', fontSize: 14, fontFamily: 'Font-SemiBold', }}> Send</Text></View></Send> ); }} renderTime={props => { let time = null; const {currentMessage} = props; if (!currentMessage.createdAt.getTime) { let utcTIme = ''; utcTIme = currentMessage.createdAt +'.000Z'; time = new Date(utcTIme); } return (<Moment style={{fontSize: 12, color: '#fff', paddingHorizontal: 5}} utcOffset="+05:30" format="HH:mm A" element={Text} local> {currentMessage.createdAt}</Moment> // <Text // style={{ // marginLeft: "auto", // marginLeft: "auto", // color: "#cecece" // }} // > // {time // ? time.toLocaleString("en-IN", { // hour: "numeric", // minute: "numeric", // hour12: true // }) // : currentMessage.createdAt.toLocaleString("en-IN", { // hour: "numeric", // minute: "numeric", // hour12: true // })} // </Text> ); }} renderUsernameOnMessage={true} /></KeyboardAvoidingView> ); } }}export default connect( MapStateToProps, mapDispatchToProps,)(Chatbox);
and my ChatService looks like this
import { Socket } from '../components/sockets/phoenix'import getEnvVars from "../../environment";const TIMEOUT = 10000const URL = `ws://${PHOENIX_HOST}/socket`;export default (token, roomToken, receiveChatMessage, renderChatMessage, renderEarlierMessages) => { // construct a socket const LOBBY = `team_room:${roomToken}`; const topicId = LOBBY.split(":").slice(-1)[0]; const socket = new Socket(URL, { params: { token: token } }) // configure the event handlers socket.onOpen(event => console.log('Connected.')) socket.onError(event => console.log('Cannot connect.')) socket.onClose(event => console.log('Goodbye.')) // open a connection to the server socket.connect() // configure a channel into a room - https://www.youtube.com/watch?v=vWFX4ylV_ko const chan = socket.channel(LOBBY, {}) // join the channel and listen for admittance chan.join() .receive('ignore', () => console.log('Access denied.')) .receive("ok", (msg) => renderChatMessage(msg)) .receive('timeout', () => console.log('Must be a MongoDB.')) // add some channel-level event handlers chan.onError(event => console.log('Channel blew up.')) chan.onClose(event => console.log('Channel closed.')) // when we receive a new chat message, just trigger the appropriate callback chan.on(`messages:${topicId}:new`, msg => { receiveChatMessage(msg) }); // you can can listen to multiple types chan.on('user:entered', msg => console.log('say hello to ', msg)) // a function to shut it all down const close = () => socket.disconnect(); const open = () => socket.connect(); // a function to send a message const send = (messages) => { let newMessage = messages[0]; chan .push("message:add", { message: newMessage.text }, TIMEOUT) .receive("ok", ({ messages }) => { analytics.track("Messages Sent", { messages: messages }); }) .receive("error", reasons => console.log("flop", reasons)) .receive("timeout", () => console.log("slow much?")); } const loadEarlier = (lastMessageId) => { chan .push("message:load_more", { last_message_id: lastMessageId }) .receive("ok", response => { renderEarlierMessages(response); }); } // reveal a couple ways to drive this bus return { open, close, send, loadEarlier }}
when in release mode the socket doesn't connect at all.
I'm not using proguard so I don't know whats wrong
my app level build.gradle looks like this
apply plugin: "com.android.application"import com.android.build.OutputFile/** * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets * and bundleReleaseJsAndAssets). * These basically call `react-native bundle` with the correct arguments during the Android build * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the * bundle directly from the development server. Below you can see all the possible configurations * and their defaults. If you decide to add a configuration block, make sure to add it before the * `apply from: "../../node_modules/react-native/react.gradle"` line. * * project.ext.react = [ * // the name of the generated asset file containing your JS bundle * bundleAssetName: "index.android.bundle", * * // the entry file for bundle generation * entryFile: "index.android.js", * * // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format * bundleCommand: "ram-bundle", * * // whether to bundle JS and assets in debug mode * bundleInDebug: false, * * // whether to bundle JS and assets in release mode * bundleInRelease: true, * * // whether to bundle JS and assets in another build variant (if configured). * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants * // The configuration property can be in the following formats * // 'bundleIn${productFlavor}${buildType}' * // 'bundleIn${buildType}' * // bundleInFreeDebug: true, * // bundleInPaidRelease: true, * // bundleInBeta: true, * * // whether to disable dev mode in custom build variants (by default only disabled in release) * // for example: to disable dev mode in the staging build type (if configured) * devDisabledInStaging: true, * // The configuration property can be in the following formats * // 'devDisabledIn${productFlavor}${buildType}' * // 'devDisabledIn${buildType}' * * // the root of your project, i.e. where "package.json" lives * root: "../../", * * // where to put the JS bundle asset in debug mode * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", * * // where to put the JS bundle asset in release mode * jsBundleDirRelease: "$buildDir/intermediates/assets/release", * * // where to put drawable resources / React Native assets, e.g. the ones you use via * // require('./image.png')), in debug mode * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", * * // where to put drawable resources / React Native assets, e.g. the ones you use via * // require('./image.png')), in release mode * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", * * // by default the gradle tasks are skipped if none of the JS files or assets change; this means * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to * // date; if you have any other folders that you want to ignore for performance reasons (gradle * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ * // for example, you might want to remove it from here. * inputExcludes: ["android/**", "ios/**"], * * // override which node gets called and with what additional arguments * nodeExecutableAndArgs: ["node"], * * // supply additional arguments to the packager * extraPackagerArgs: [] * ] */project.ext.react = [ entryFile: "index.js", enableHermes: false, // clean and rebuild if changing]apply from: "../../node_modules/react-native/react.gradle"apply from: '../../node_modules/react-native-unimodules/gradle.groovy'/** * Set this to true to create two separate APKs instead of one: * - An APK that only works on ARM devices * - An APK that only works on x86 devices * The advantage is the size of the APK is reduced by about 4MB. * Upload all the APKs to the Play Store and people will download * the correct one based on the CPU architecture of their device. */def enableSeparateBuildPerCPUArchitecture = false/** * Run Proguard to shrink the Java bytecode in release builds. */def enableProguardInReleaseBuilds = false/** * The preferred build flavor of JavaScriptCore. * * For example, to use the international variant, you can use: * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` * * The international variant includes ICU i18n library and necessary data * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * give correct results when using with locales other than en-US. Note that * this variant is about 6MiB larger per architecture than default. */def jscFlavor = 'org.webkit:android-jsc:+'/** * Whether to enable the Hermes VM. * * This should be set on project.ext.react and mirrored here. If it is not set * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode * and the benefits of using Hermes will therefore be sharply reduced. */def enableHermes = project.ext.react.get("enableHermes", false);def keystorePropertiesFile = rootProject.file("keystore.properties");def keystoreProperties = new Properties()keystoreProperties.load(new FileInputStream(keystorePropertiesFile))android { compileSdkVersion rootProject.ext.compileSdkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } dexOptions { javaMaxHeapSize "4g" } defaultConfig { applicationId "com.chatapp" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false // If true, also generate a universal APK include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } release { storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] } } buildTypes { debug { signingConfig signingConfigs.debug } release { // Caution! In production, you need to generate your own keystore file. // see https://facebook.github.io/react-native/docs/signed-apk-android. signingConfig signingConfigs.debug 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: // https://developer.android.com/studio/build/configure-apk-splits.html def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 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 } } } packagingOptions { pickFirst 'lib/x86/libc++_shared.so' pickFirst 'lib/x86_64/libjsc.so' pickFirst 'lib/arm64-v8a/libjsc.so' pickFirst 'lib/arm64-v8a/libc++_shared.so' pickFirst 'lib/x86_64/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' }}dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "com.facebook.react:react-native:+" // From node_modules implementation project(':react-native-google-signin') implementation 'com.facebook.fresco:fresco:2.0.0' implementation 'com.facebook.fresco:animated-gif:2.0.0' implementation project(':react-native-notifications') implementation 'com.google.firebase:firebase-core:16.0.0' if (enableHermes) { def hermesPath = "../../node_modules/hermes-engine/android/"; debugImplementation files(hermesPath +"hermes-debug.aar") releaseImplementation files(hermesPath +"hermes-release.aar") } else { implementation jscFlavor } addUnimodulesDependencies()}// Run this once to be able to run the application with BUCK// puts all compile dependencies into folder libs for BUCK to usetask copyDownloadableDepsToLibs(type: Copy) { from configurations.compile into 'libs'}apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)apply plugin: 'com.google.gms.google-services'com.google.gms.googleservices.GoogleServicesPlugin.config.disableVersionCheck = true