ChatService не работает на app-release.apk - PullRequest
0 голосов
/ 16 апреля 2020

В моем приложении есть класс chatService, который хорошо работает в режиме отладки, но совсем не работает, когда я выпускаю apk-релиз приложения.

Мой файл компонента чата выглядит следующим образом

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);

и мой ChatService выглядит следующим образом

import { Socket } from '../components/sockets/phoenix'
import getEnvVars from "../../environment";
const TIMEOUT = 10000
const 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 }
}

, когда в режиме выпуска сокет вообще не подключается.

Я не использую proguard, поэтому я не не знаю, что не так

мой уровень приложения build.gradle выглядит следующим образом


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 use
task 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...