packages = new PackageList(this).getPackages();
27 | // Packages that cannot be autolinked yet can be added manually here, for example:
28 | // packages.add(new MyReactNativePackage());
29 | return packages;
30 | }
31 |
32 | @Override
33 | protected String getJSMainModuleName() {
34 | return "index";
35 | }
36 | };
37 |
38 | @Override
39 | public ReactNativeHost getReactNativeHost() {
40 | return mReactNativeHost;
41 | }
42 |
43 | @Override
44 | public void onCreate() {
45 | super.onCreate();
46 | SoLoader.init(this, /* native exopackage */ false);
47 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
48 | }
49 |
50 | /**
51 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
52 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
53 | *
54 | * @param context
55 | * @param reactInstanceManager
56 | */
57 | private static void initializeFlipper(
58 | Context context, ReactInstanceManager reactInstanceManager) {
59 | if (BuildConfig.DEBUG) {
60 | try {
61 | /*
62 | We use reflection here to pick up the class that initializes Flipper,
63 | since Flipper library is not available in release mode
64 | */
65 | Class> aClass = Class.forName("com.react_native_twilio_chat.ReactNativeFlipper");
66 | aClass
67 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
68 | .invoke(null, context, reactInstanceManager);
69 | } catch (ClassNotFoundException e) {
70 | e.printStackTrace();
71 | } catch (NoSuchMethodException e) {
72 | e.printStackTrace();
73 | } catch (IllegalAccessException e) {
74 | e.printStackTrace();
75 | } catch (InvocationTargetException e) {
76 | e.printStackTrace();
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/screens/chat-room/chat-room-screen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useCallback, useEffect, useRef } from 'react';
2 | import { StyleSheet, View } from 'react-native';
3 | import { GiftedChat } from 'react-native-gifted-chat';
4 | import { showMessage } from 'react-native-flash-message';
5 |
6 | import { colors } from '../../theme';
7 | import { TwilioService } from '../../services/twilio-service';
8 | import { ChatLoader } from './components/chat-loader';
9 |
10 | export function ChatRoomScreen({ route }) {
11 | const { channelId, identity } = route.params;
12 | const [messages, setMessages] = useState([]);
13 | const [loading, setLoading] = useState(true);
14 | const chatClientChannel = useRef();
15 | const chatMessagesPaginator = useRef();
16 |
17 | const setChannelEvents = useCallback((channel) => {
18 | chatClientChannel.current = channel;
19 | chatClientChannel.current.on('messageAdded', (message) => {
20 | const newMessage = TwilioService.getInstance().parseMessage(message);
21 | const { giftedId } = message.attributes;
22 | if (giftedId) {
23 | setMessages((prevMessages) => {
24 | if (prevMessages.some(({ _id }) => _id === giftedId)) {
25 | return prevMessages.map((m) => (m._id === giftedId ? newMessage : m));
26 | }
27 | return [newMessage, ...prevMessages];
28 | });
29 | }
30 | });
31 | return chatClientChannel.current;
32 | }, []);
33 |
34 | useEffect(() => {
35 | TwilioService.getInstance()
36 | .getChatClient()
37 | .then((client) => client.getChannelBySid(channelId))
38 | .then((channel) => setChannelEvents(channel))
39 | .then((currentChannel) => currentChannel.getMessages())
40 | .then((paginator) => {
41 | chatMessagesPaginator.current = paginator;
42 | const newMessages = TwilioService.getInstance().parseMessages(paginator.items);
43 | setMessages(newMessages);
44 | })
45 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
46 | .finally(() => setLoading(false));
47 | }, [channelId, setChannelEvents]);
48 |
49 | const onSend = useCallback((newMessages = []) => {
50 | const attributes = { giftedId: newMessages[0]._id };
51 | setMessages((prevMessages) => GiftedChat.append(prevMessages, newMessages));
52 | chatClientChannel.current?.sendMessage(newMessages[0].text, attributes);
53 | }, []);
54 |
55 | return (
56 |
57 | {loading ? (
58 |
59 | ) : (
60 | onSend(messages)}
65 | user={{ _id: identity }}
66 | />
67 | )}
68 |
69 | );
70 | }
71 |
72 | const styles = StyleSheet.create({
73 | screen: {
74 | flexGrow: 1,
75 | backgroundColor: colors.white,
76 | },
77 | messageContainer: {
78 | backgroundColor: colors.snow,
79 | },
80 | });
81 |
--------------------------------------------------------------------------------
/src/screens/chat-create/chat-create-screen.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { View, Text, TextInput, StyleSheet, Image, TouchableOpacity } from 'react-native';
3 | import { showMessage } from 'react-native-flash-message';
4 |
5 | import { colors } from '../../theme';
6 | import { images } from '../../assets';
7 | import { TwilioService } from '../../services/twilio-service';
8 | import { LoadingOverlay } from '../../components';
9 | import { useApp } from '../../app-context';
10 |
11 | export function ChatCreateScreen() {
12 | const [channelName, setChannelName] = useState('');
13 | const [loading, setLoading] = useState(false);
14 | const { channels, updateChannels } = useApp();
15 |
16 | const onAddChannel = (channel) => {
17 | const newChannel = TwilioService.getInstance().parseChannel(channel);
18 | updateChannels(channels.concat(newChannel));
19 | };
20 |
21 | const onCreateOrJoin = () => {
22 | setLoading(true);
23 | TwilioService.getInstance()
24 | .getChatClient()
25 | .then((client) =>
26 | client
27 | .getChannelByUniqueName(channelName)
28 | .then((channel) => (channel.channelState.status !== 'joined' ? channel.join() : channel))
29 | .then(onAddChannel)
30 | .catch(() =>
31 | client.createChannel({ uniqueName: channelName, friendlyName: channelName }).then((channel) => {
32 | onAddChannel(channel);
33 | channel.join();
34 | }),
35 | ),
36 | )
37 | .then(() => showMessage({ message: 'You have joined.' }))
38 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
39 | .finally(() => setLoading(false));
40 | };
41 |
42 | return (
43 |
44 |
45 |
52 |
53 | Create Or Join
54 |
55 | {loading && }
56 |
57 | );
58 | }
59 |
60 | const styles = StyleSheet.create({
61 | screen: {
62 | flex: 1,
63 | alignItems: 'center',
64 | justifyContent: 'center',
65 | backgroundColor: colors.whisper,
66 | },
67 | logo: {
68 | width: 120,
69 | height: 120,
70 | marginBottom: 32,
71 | },
72 | input: {
73 | width: 280,
74 | height: 50,
75 | padding: 12,
76 | fontSize: 16,
77 | borderRadius: 8,
78 | borderWidth: 1,
79 | borderColor: colors.eclipse,
80 | marginTop: 32,
81 | marginBottom: 16,
82 | },
83 | button: {
84 | width: 280,
85 | height: 50,
86 | backgroundColor: colors.malibu,
87 | borderRadius: 8,
88 | alignItems: 'center',
89 | justifyContent: 'center',
90 | },
91 | buttonText: {
92 | fontSize: 17,
93 | color: colors.white,
94 | },
95 | });
96 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto init
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto init
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :init
68 | @rem Get command-line arguments, handling Windows variants
69 |
70 | if not "%OS%" == "Windows_NT" goto win9xME_args
71 |
72 | :win9xME_args
73 | @rem Slurp the command line arguments.
74 | set CMD_LINE_ARGS=
75 | set _SKIP=2
76 |
77 | :win9xME_args_slurp
78 | if "x%~1" == "x" goto execute
79 |
80 | set CMD_LINE_ARGS=%*
81 |
82 | :execute
83 | @rem Setup the command line
84 |
85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86 |
87 | @rem Execute Gradle
88 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
89 |
90 | :end
91 | @rem End local scope for the variables with windows NT shell
92 | if "%ERRORLEVEL%"=="0" goto mainEnd
93 |
94 | :fail
95 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
96 | rem the _cmd.exe /c_ return code!
97 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
98 | exit /b 1
99 |
100 | :mainEnd
101 | if "%OS%"=="Windows_NT" endlocal
102 |
103 | :omega
104 |
--------------------------------------------------------------------------------
/android/app/src/debug/java/com/react_native_twilio_chat/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | * This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.react_native_twilio_chat;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceManager;
23 | import com.facebook.react.bridge.ReactContext;
24 | import com.facebook.react.modules.network.NetworkingModule;
25 | import okhttp3.OkHttpClient;
26 |
27 | public class ReactNativeFlipper {
28 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
29 | if (FlipperUtils.shouldEnableFlipper(context)) {
30 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
31 |
32 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
33 | client.addPlugin(new ReactFlipperPlugin());
34 | client.addPlugin(new DatabasesFlipperPlugin(context));
35 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
36 | client.addPlugin(CrashReporterPlugin.getInstance());
37 |
38 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
39 | NetworkingModule.setCustomClientBuilder(
40 | new NetworkingModule.CustomClientBuilder() {
41 | @Override
42 | public void apply(OkHttpClient.Builder builder) {
43 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
44 | }
45 | });
46 | client.addPlugin(networkFlipperPlugin);
47 | client.start();
48 |
49 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
50 | // Hence we run if after all native modules have been initialized
51 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
52 | if (reactContext == null) {
53 | reactInstanceManager.addReactInstanceEventListener(
54 | new ReactInstanceManager.ReactInstanceEventListener() {
55 | @Override
56 | public void onReactContextInitialized(ReactContext reactContext) {
57 | reactInstanceManager.removeReactInstanceEventListener(this);
58 | reactContext.runOnNativeModulesQueueThread(
59 | new Runnable() {
60 | @Override
61 | public void run() {
62 | client.addPlugin(new FrescoFlipperPlugin());
63 | }
64 | });
65 | }
66 | });
67 | } else {
68 | client.addPlugin(new FrescoFlipperPlugin());
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/ios/react_native_twilio_chat.xcodeproj/xcshareddata/xcschemes/react_native_twilio_chat.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/ios/react_native_twilio_chat.xcodeproj/xcshareddata/xcschemes/react_native_twilio_chat-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/screens/chat-list/chat-list-screen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useLayoutEffect, useEffect, useCallback, useRef, useMemo } from 'react';
2 | import { View, Text, StyleSheet, FlatList, TouchableOpacity } from 'react-native';
3 | import { showMessage } from 'react-native-flash-message';
4 |
5 | import { colors } from '../../theme';
6 | import { routes } from '../../app';
7 | import { TwilioService } from '../../services/twilio-service';
8 | import { getToken } from '../../services/api-service';
9 | import { useApp } from '../../app-context';
10 |
11 | import { ChatListLoader } from './components/chat-list-loader';
12 | import { ChatListEmpty } from './components/chat-list-empty';
13 | import { ChatListItem } from './components/chat-list-item';
14 |
15 | export function ChatListScreen({ navigation, route }) {
16 | const { username } = route.params;
17 | const [loading, setLoading] = useState(true);
18 | const { channels, updateChannels } = useApp();
19 | const channelPaginator = useRef();
20 |
21 | useLayoutEffect(() => {
22 | navigation.setOptions({
23 | headerRight: () => (
24 | navigation.navigate(routes.ChatCreat.name)}>
25 | +
26 |
27 | ),
28 | });
29 | }, [navigation]);
30 |
31 | const setChannelEvents = useCallback(
32 | (client) => {
33 | client.on('messageAdded', (message) => {
34 | updateChannels((prevChannels) =>
35 | prevChannels.map((channel) =>
36 | channel.id === message.channel.sid ? { ...channel, lastMessageTime: message.dateCreated } : channel,
37 | ),
38 | );
39 | });
40 | return client;
41 | },
42 | [updateChannels],
43 | );
44 |
45 | const getSubscribedChannels = useCallback(
46 | (client) =>
47 | client.getSubscribedChannels().then((paginator) => {
48 | channelPaginator.current = paginator;
49 | const newChannels = TwilioService.getInstance().parseChannels(channelPaginator.current.items);
50 | updateChannels(newChannels);
51 | }),
52 | [updateChannels],
53 | );
54 |
55 | useEffect(() => {
56 | getToken(username)
57 | .then((token) => TwilioService.getInstance().getChatClient(token))
58 | .then(() => TwilioService.getInstance().addTokenListener(getToken))
59 | .then(setChannelEvents)
60 | .then(getSubscribedChannels)
61 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
62 | .finally(() => setLoading(false));
63 |
64 | return () => TwilioService.getInstance().clientShutdown();
65 | }, [username, setChannelEvents, getSubscribedChannels]);
66 |
67 | const sortedChannels = useMemo(
68 | () => channels.sort((channelA, channelB) => channelB.lastMessageTime - channelA.lastMessageTime),
69 | [channels],
70 | );
71 |
72 | return (
73 |
74 | {loading ? (
75 |
76 | ) : (
77 | item.id}
80 | renderItem={({ item }) => (
81 | navigation.navigate(routes.ChatRoom.name, { channelId: item.id, identity: username })}
84 | />
85 | )}
86 | ListEmptyComponent={ }
87 | />
88 | )}
89 |
90 | );
91 | }
92 |
93 | const styles = StyleSheet.create({
94 | screen: {
95 | flex: 1,
96 | backgroundColor: colors.snow,
97 | },
98 | addButton: {
99 | height: 24,
100 | width: 24,
101 | alignItems: 'center',
102 | justifyContent: 'center',
103 | marginRight: 8,
104 | },
105 | addButtonText: {
106 | fontSize: 22,
107 | fontWeight: '700',
108 | lineHeight: 24,
109 | color: colors.white,
110 | },
111 | });
112 |
--------------------------------------------------------------------------------
/ios/react_native_twilio_chat/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin or MSYS, switch paths to Windows format before running java
129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=`expr $i + 1`
158 | done
159 | case $i in
160 | 0) set -- ;;
161 | 1) set -- "$args0" ;;
162 | 2) set -- "$args0" "$args1" ;;
163 | 3) set -- "$args0" "$args1" "$args2" ;;
164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=`save "$@"`
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | exec "$JAVACMD" "$@"
184 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation. If none specified and
19 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is
20 | * // default. Can be overridden with ENTRY_FILE environment variable.
21 | * entryFile: "index.android.js",
22 | *
23 | * // https://reactnative.dev/docs/performance#enable-the-ram-format
24 | * bundleCommand: "ram-bundle",
25 | *
26 | * // whether to bundle JS and assets in debug mode
27 | * bundleInDebug: false,
28 | *
29 | * // whether to bundle JS and assets in release mode
30 | * bundleInRelease: true,
31 | *
32 | * // whether to bundle JS and assets in another build variant (if configured).
33 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
34 | * // The configuration property can be in the following formats
35 | * // 'bundleIn${productFlavor}${buildType}'
36 | * // 'bundleIn${buildType}'
37 | * // bundleInFreeDebug: true,
38 | * // bundleInPaidRelease: true,
39 | * // bundleInBeta: true,
40 | *
41 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
42 | * // for example: to disable dev mode in the staging build type (if configured)
43 | * devDisabledInStaging: true,
44 | * // The configuration property can be in the following formats
45 | * // 'devDisabledIn${productFlavor}${buildType}'
46 | * // 'devDisabledIn${buildType}'
47 | *
48 | * // the root of your project, i.e. where "package.json" lives
49 | * root: "../../",
50 | *
51 | * // where to put the JS bundle asset in debug mode
52 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
53 | *
54 | * // where to put the JS bundle asset in release mode
55 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
56 | *
57 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
58 | * // require('./image.png')), in debug mode
59 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
60 | *
61 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
62 | * // require('./image.png')), in release mode
63 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
64 | *
65 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
66 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
67 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
68 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
69 | * // for example, you might want to remove it from here.
70 | * inputExcludes: ["android/**", "ios/**"],
71 | *
72 | * // override which node gets called and with what additional arguments
73 | * nodeExecutableAndArgs: ["node"],
74 | *
75 | * // supply additional arguments to the packager
76 | * extraPackagerArgs: []
77 | * ]
78 | */
79 |
80 | project.ext.react = [
81 | enableHermes: false, // clean and rebuild if changing
82 | ]
83 |
84 | apply from: "../../node_modules/react-native/react.gradle"
85 |
86 | /**
87 | * Set this to true to create two separate APKs instead of one:
88 | * - An APK that only works on ARM devices
89 | * - An APK that only works on x86 devices
90 | * The advantage is the size of the APK is reduced by about 4MB.
91 | * Upload all the APKs to the Play Store and people will download
92 | * the correct one based on the CPU architecture of their device.
93 | */
94 | def enableSeparateBuildPerCPUArchitecture = false
95 |
96 | /**
97 | * Run Proguard to shrink the Java bytecode in release builds.
98 | */
99 | def enableProguardInReleaseBuilds = false
100 |
101 | /**
102 | * The preferred build flavor of JavaScriptCore.
103 | *
104 | * For example, to use the international variant, you can use:
105 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
106 | *
107 | * The international variant includes ICU i18n library and necessary data
108 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
109 | * give correct results when using with locales other than en-US. Note that
110 | * this variant is about 6MiB larger per architecture than default.
111 | */
112 | def jscFlavor = 'org.webkit:android-jsc:+'
113 |
114 | /**
115 | * Whether to enable the Hermes VM.
116 | *
117 | * This should be set on project.ext.react and mirrored here. If it is not set
118 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
119 | * and the benefits of using Hermes will therefore be sharply reduced.
120 | */
121 | def enableHermes = project.ext.react.get("enableHermes", false);
122 |
123 | android {
124 | compileSdkVersion rootProject.ext.compileSdkVersion
125 |
126 | compileOptions {
127 | sourceCompatibility JavaVersion.VERSION_1_8
128 | targetCompatibility JavaVersion.VERSION_1_8
129 | }
130 |
131 | defaultConfig {
132 | applicationId "com.react_native_twilio_chat"
133 | minSdkVersion rootProject.ext.minSdkVersion
134 | targetSdkVersion rootProject.ext.targetSdkVersion
135 | versionCode 1
136 | versionName "1.0"
137 | }
138 | splits {
139 | abi {
140 | reset()
141 | enable enableSeparateBuildPerCPUArchitecture
142 | universalApk false // If true, also generate a universal APK
143 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
144 | }
145 | }
146 | signingConfigs {
147 | debug {
148 | storeFile file('debug.keystore')
149 | storePassword 'android'
150 | keyAlias 'androiddebugkey'
151 | keyPassword 'android'
152 | }
153 | }
154 | buildTypes {
155 | debug {
156 | signingConfig signingConfigs.debug
157 | }
158 | release {
159 | // Caution! In production, you need to generate your own keystore file.
160 | // see https://reactnative.dev/docs/signed-apk-android.
161 | signingConfig signingConfigs.debug
162 | minifyEnabled enableProguardInReleaseBuilds
163 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
164 | }
165 | }
166 |
167 | // applicationVariants are e.g. debug, release
168 | applicationVariants.all { variant ->
169 | variant.outputs.each { output ->
170 | // For each separate APK per architecture, set a unique version code as described here:
171 | // https://developer.android.com/studio/build/configure-apk-splits.html
172 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
173 | def abi = output.getFilter(OutputFile.ABI)
174 | if (abi != null) { // null for the universal-debug, universal-release variants
175 | output.versionCodeOverride =
176 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
177 | }
178 |
179 | }
180 | }
181 | }
182 |
183 | dependencies {
184 | implementation fileTree(dir: "libs", include: ["*.jar"])
185 | //noinspection GradleDynamicVersion
186 | implementation "com.facebook.react:react-native:+" // From node_modules
187 |
188 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
189 |
190 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
191 | exclude group:'com.facebook.fbjni'
192 | }
193 |
194 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
195 | exclude group:'com.facebook.flipper'
196 | exclude group:'com.squareup.okhttp3', module:'okhttp'
197 | }
198 |
199 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
200 | exclude group:'com.facebook.flipper'
201 | }
202 |
203 | if (enableHermes) {
204 | def hermesPath = "../../node_modules/hermes-engine/android/";
205 | debugImplementation files(hermesPath + "hermes-debug.aar")
206 | releaseImplementation files(hermesPath + "hermes-release.aar")
207 | } else {
208 | implementation jscFlavor
209 | }
210 | }
211 |
212 | // Run this once to be able to run the application with BUCK
213 | // puts all compile dependencies into folder libs for BUCK to use
214 | task copyDownloadableDepsToLibs(type: Copy) {
215 | from configurations.compile
216 | into 'libs'
217 | }
218 |
219 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
220 |
--------------------------------------------------------------------------------
/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - boost-for-react-native (1.63.0)
3 | - CocoaAsyncSocket (7.6.5)
4 | - CocoaLibEvent (1.0.0)
5 | - DoubleConversion (1.1.6)
6 | - FBLazyVector (0.63.4)
7 | - FBReactNativeSpec (0.63.4):
8 | - Folly (= 2020.01.13.00)
9 | - RCTRequired (= 0.63.4)
10 | - RCTTypeSafety (= 0.63.4)
11 | - React-Core (= 0.63.4)
12 | - React-jsi (= 0.63.4)
13 | - ReactCommon/turbomodule/core (= 0.63.4)
14 | - Flipper (0.54.0):
15 | - Flipper-Folly (~> 2.2)
16 | - Flipper-RSocket (~> 1.1)
17 | - Flipper-DoubleConversion (1.1.7)
18 | - Flipper-Folly (2.3.0):
19 | - boost-for-react-native
20 | - CocoaLibEvent (~> 1.0)
21 | - Flipper-DoubleConversion
22 | - Flipper-Glog
23 | - OpenSSL-Universal (= 1.0.2.20)
24 | - Flipper-Glog (0.3.6)
25 | - Flipper-PeerTalk (0.0.4)
26 | - Flipper-RSocket (1.1.0):
27 | - Flipper-Folly (~> 2.2)
28 | - FlipperKit (0.54.0):
29 | - FlipperKit/Core (= 0.54.0)
30 | - FlipperKit/Core (0.54.0):
31 | - Flipper (~> 0.54.0)
32 | - FlipperKit/CppBridge
33 | - FlipperKit/FBCxxFollyDynamicConvert
34 | - FlipperKit/FBDefines
35 | - FlipperKit/FKPortForwarding
36 | - FlipperKit/CppBridge (0.54.0):
37 | - Flipper (~> 0.54.0)
38 | - FlipperKit/FBCxxFollyDynamicConvert (0.54.0):
39 | - Flipper-Folly (~> 2.2)
40 | - FlipperKit/FBDefines (0.54.0)
41 | - FlipperKit/FKPortForwarding (0.54.0):
42 | - CocoaAsyncSocket (~> 7.6)
43 | - Flipper-PeerTalk (~> 0.0.4)
44 | - FlipperKit/FlipperKitHighlightOverlay (0.54.0)
45 | - FlipperKit/FlipperKitLayoutPlugin (0.54.0):
46 | - FlipperKit/Core
47 | - FlipperKit/FlipperKitHighlightOverlay
48 | - FlipperKit/FlipperKitLayoutTextSearchable
49 | - YogaKit (~> 1.18)
50 | - FlipperKit/FlipperKitLayoutTextSearchable (0.54.0)
51 | - FlipperKit/FlipperKitNetworkPlugin (0.54.0):
52 | - FlipperKit/Core
53 | - FlipperKit/FlipperKitReactPlugin (0.54.0):
54 | - FlipperKit/Core
55 | - FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0):
56 | - FlipperKit/Core
57 | - FlipperKit/SKIOSNetworkPlugin (0.54.0):
58 | - FlipperKit/Core
59 | - FlipperKit/FlipperKitNetworkPlugin
60 | - Folly (2020.01.13.00):
61 | - boost-for-react-native
62 | - DoubleConversion
63 | - Folly/Default (= 2020.01.13.00)
64 | - glog
65 | - Folly/Default (2020.01.13.00):
66 | - boost-for-react-native
67 | - DoubleConversion
68 | - glog
69 | - glog (0.3.5)
70 | - OpenSSL-Universal (1.0.2.20):
71 | - OpenSSL-Universal/Static (= 1.0.2.20)
72 | - OpenSSL-Universal/Static (1.0.2.20)
73 | - RCTRequired (0.63.4)
74 | - RCTTypeSafety (0.63.4):
75 | - FBLazyVector (= 0.63.4)
76 | - Folly (= 2020.01.13.00)
77 | - RCTRequired (= 0.63.4)
78 | - React-Core (= 0.63.4)
79 | - React (0.63.4):
80 | - React-Core (= 0.63.4)
81 | - React-Core/DevSupport (= 0.63.4)
82 | - React-Core/RCTWebSocket (= 0.63.4)
83 | - React-RCTActionSheet (= 0.63.4)
84 | - React-RCTAnimation (= 0.63.4)
85 | - React-RCTBlob (= 0.63.4)
86 | - React-RCTImage (= 0.63.4)
87 | - React-RCTLinking (= 0.63.4)
88 | - React-RCTNetwork (= 0.63.4)
89 | - React-RCTSettings (= 0.63.4)
90 | - React-RCTText (= 0.63.4)
91 | - React-RCTVibration (= 0.63.4)
92 | - React-callinvoker (0.63.4)
93 | - React-Core (0.63.4):
94 | - Folly (= 2020.01.13.00)
95 | - glog
96 | - React-Core/Default (= 0.63.4)
97 | - React-cxxreact (= 0.63.4)
98 | - React-jsi (= 0.63.4)
99 | - React-jsiexecutor (= 0.63.4)
100 | - Yoga
101 | - React-Core/CoreModulesHeaders (0.63.4):
102 | - Folly (= 2020.01.13.00)
103 | - glog
104 | - React-Core/Default
105 | - React-cxxreact (= 0.63.4)
106 | - React-jsi (= 0.63.4)
107 | - React-jsiexecutor (= 0.63.4)
108 | - Yoga
109 | - React-Core/Default (0.63.4):
110 | - Folly (= 2020.01.13.00)
111 | - glog
112 | - React-cxxreact (= 0.63.4)
113 | - React-jsi (= 0.63.4)
114 | - React-jsiexecutor (= 0.63.4)
115 | - Yoga
116 | - React-Core/DevSupport (0.63.4):
117 | - Folly (= 2020.01.13.00)
118 | - glog
119 | - React-Core/Default (= 0.63.4)
120 | - React-Core/RCTWebSocket (= 0.63.4)
121 | - React-cxxreact (= 0.63.4)
122 | - React-jsi (= 0.63.4)
123 | - React-jsiexecutor (= 0.63.4)
124 | - React-jsinspector (= 0.63.4)
125 | - Yoga
126 | - React-Core/RCTActionSheetHeaders (0.63.4):
127 | - Folly (= 2020.01.13.00)
128 | - glog
129 | - React-Core/Default
130 | - React-cxxreact (= 0.63.4)
131 | - React-jsi (= 0.63.4)
132 | - React-jsiexecutor (= 0.63.4)
133 | - Yoga
134 | - React-Core/RCTAnimationHeaders (0.63.4):
135 | - Folly (= 2020.01.13.00)
136 | - glog
137 | - React-Core/Default
138 | - React-cxxreact (= 0.63.4)
139 | - React-jsi (= 0.63.4)
140 | - React-jsiexecutor (= 0.63.4)
141 | - Yoga
142 | - React-Core/RCTBlobHeaders (0.63.4):
143 | - Folly (= 2020.01.13.00)
144 | - glog
145 | - React-Core/Default
146 | - React-cxxreact (= 0.63.4)
147 | - React-jsi (= 0.63.4)
148 | - React-jsiexecutor (= 0.63.4)
149 | - Yoga
150 | - React-Core/RCTImageHeaders (0.63.4):
151 | - Folly (= 2020.01.13.00)
152 | - glog
153 | - React-Core/Default
154 | - React-cxxreact (= 0.63.4)
155 | - React-jsi (= 0.63.4)
156 | - React-jsiexecutor (= 0.63.4)
157 | - Yoga
158 | - React-Core/RCTLinkingHeaders (0.63.4):
159 | - Folly (= 2020.01.13.00)
160 | - glog
161 | - React-Core/Default
162 | - React-cxxreact (= 0.63.4)
163 | - React-jsi (= 0.63.4)
164 | - React-jsiexecutor (= 0.63.4)
165 | - Yoga
166 | - React-Core/RCTNetworkHeaders (0.63.4):
167 | - Folly (= 2020.01.13.00)
168 | - glog
169 | - React-Core/Default
170 | - React-cxxreact (= 0.63.4)
171 | - React-jsi (= 0.63.4)
172 | - React-jsiexecutor (= 0.63.4)
173 | - Yoga
174 | - React-Core/RCTSettingsHeaders (0.63.4):
175 | - Folly (= 2020.01.13.00)
176 | - glog
177 | - React-Core/Default
178 | - React-cxxreact (= 0.63.4)
179 | - React-jsi (= 0.63.4)
180 | - React-jsiexecutor (= 0.63.4)
181 | - Yoga
182 | - React-Core/RCTTextHeaders (0.63.4):
183 | - Folly (= 2020.01.13.00)
184 | - glog
185 | - React-Core/Default
186 | - React-cxxreact (= 0.63.4)
187 | - React-jsi (= 0.63.4)
188 | - React-jsiexecutor (= 0.63.4)
189 | - Yoga
190 | - React-Core/RCTVibrationHeaders (0.63.4):
191 | - Folly (= 2020.01.13.00)
192 | - glog
193 | - React-Core/Default
194 | - React-cxxreact (= 0.63.4)
195 | - React-jsi (= 0.63.4)
196 | - React-jsiexecutor (= 0.63.4)
197 | - Yoga
198 | - React-Core/RCTWebSocket (0.63.4):
199 | - Folly (= 2020.01.13.00)
200 | - glog
201 | - React-Core/Default (= 0.63.4)
202 | - React-cxxreact (= 0.63.4)
203 | - React-jsi (= 0.63.4)
204 | - React-jsiexecutor (= 0.63.4)
205 | - Yoga
206 | - React-CoreModules (0.63.4):
207 | - FBReactNativeSpec (= 0.63.4)
208 | - Folly (= 2020.01.13.00)
209 | - RCTTypeSafety (= 0.63.4)
210 | - React-Core/CoreModulesHeaders (= 0.63.4)
211 | - React-jsi (= 0.63.4)
212 | - React-RCTImage (= 0.63.4)
213 | - ReactCommon/turbomodule/core (= 0.63.4)
214 | - React-cxxreact (0.63.4):
215 | - boost-for-react-native (= 1.63.0)
216 | - DoubleConversion
217 | - Folly (= 2020.01.13.00)
218 | - glog
219 | - React-callinvoker (= 0.63.4)
220 | - React-jsinspector (= 0.63.4)
221 | - React-jsi (0.63.4):
222 | - boost-for-react-native (= 1.63.0)
223 | - DoubleConversion
224 | - Folly (= 2020.01.13.00)
225 | - glog
226 | - React-jsi/Default (= 0.63.4)
227 | - React-jsi/Default (0.63.4):
228 | - boost-for-react-native (= 1.63.0)
229 | - DoubleConversion
230 | - Folly (= 2020.01.13.00)
231 | - glog
232 | - React-jsiexecutor (0.63.4):
233 | - DoubleConversion
234 | - Folly (= 2020.01.13.00)
235 | - glog
236 | - React-cxxreact (= 0.63.4)
237 | - React-jsi (= 0.63.4)
238 | - React-jsinspector (0.63.4)
239 | - react-native-safe-area-context (3.1.9):
240 | - React-Core
241 | - React-RCTActionSheet (0.63.4):
242 | - React-Core/RCTActionSheetHeaders (= 0.63.4)
243 | - React-RCTAnimation (0.63.4):
244 | - FBReactNativeSpec (= 0.63.4)
245 | - Folly (= 2020.01.13.00)
246 | - RCTTypeSafety (= 0.63.4)
247 | - React-Core/RCTAnimationHeaders (= 0.63.4)
248 | - React-jsi (= 0.63.4)
249 | - ReactCommon/turbomodule/core (= 0.63.4)
250 | - React-RCTBlob (0.63.4):
251 | - FBReactNativeSpec (= 0.63.4)
252 | - Folly (= 2020.01.13.00)
253 | - React-Core/RCTBlobHeaders (= 0.63.4)
254 | - React-Core/RCTWebSocket (= 0.63.4)
255 | - React-jsi (= 0.63.4)
256 | - React-RCTNetwork (= 0.63.4)
257 | - ReactCommon/turbomodule/core (= 0.63.4)
258 | - React-RCTImage (0.63.4):
259 | - FBReactNativeSpec (= 0.63.4)
260 | - Folly (= 2020.01.13.00)
261 | - RCTTypeSafety (= 0.63.4)
262 | - React-Core/RCTImageHeaders (= 0.63.4)
263 | - React-jsi (= 0.63.4)
264 | - React-RCTNetwork (= 0.63.4)
265 | - ReactCommon/turbomodule/core (= 0.63.4)
266 | - React-RCTLinking (0.63.4):
267 | - FBReactNativeSpec (= 0.63.4)
268 | - React-Core/RCTLinkingHeaders (= 0.63.4)
269 | - React-jsi (= 0.63.4)
270 | - ReactCommon/turbomodule/core (= 0.63.4)
271 | - React-RCTNetwork (0.63.4):
272 | - FBReactNativeSpec (= 0.63.4)
273 | - Folly (= 2020.01.13.00)
274 | - RCTTypeSafety (= 0.63.4)
275 | - React-Core/RCTNetworkHeaders (= 0.63.4)
276 | - React-jsi (= 0.63.4)
277 | - ReactCommon/turbomodule/core (= 0.63.4)
278 | - React-RCTSettings (0.63.4):
279 | - FBReactNativeSpec (= 0.63.4)
280 | - Folly (= 2020.01.13.00)
281 | - RCTTypeSafety (= 0.63.4)
282 | - React-Core/RCTSettingsHeaders (= 0.63.4)
283 | - React-jsi (= 0.63.4)
284 | - ReactCommon/turbomodule/core (= 0.63.4)
285 | - React-RCTText (0.63.4):
286 | - React-Core/RCTTextHeaders (= 0.63.4)
287 | - React-RCTVibration (0.63.4):
288 | - FBReactNativeSpec (= 0.63.4)
289 | - Folly (= 2020.01.13.00)
290 | - React-Core/RCTVibrationHeaders (= 0.63.4)
291 | - React-jsi (= 0.63.4)
292 | - ReactCommon/turbomodule/core (= 0.63.4)
293 | - ReactCommon/turbomodule/core (0.63.4):
294 | - DoubleConversion
295 | - Folly (= 2020.01.13.00)
296 | - glog
297 | - React-callinvoker (= 0.63.4)
298 | - React-Core (= 0.63.4)
299 | - React-cxxreact (= 0.63.4)
300 | - React-jsi (= 0.63.4)
301 | - RNCMaskedView (0.1.10):
302 | - React
303 | - RNGestureHandler (1.9.0):
304 | - React-Core
305 | - RNReanimated (1.13.2):
306 | - React-Core
307 | - RNScreens (2.16.1):
308 | - React-Core
309 | - Yoga (1.14.0)
310 | - YogaKit (1.18.1):
311 | - Yoga (~> 1.14)
312 |
313 | DEPENDENCIES:
314 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
315 | - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
316 | - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
317 | - Flipper (~> 0.54.0)
318 | - Flipper-DoubleConversion (= 1.1.7)
319 | - Flipper-Folly (~> 2.2)
320 | - Flipper-Glog (= 0.3.6)
321 | - Flipper-PeerTalk (~> 0.0.4)
322 | - Flipper-RSocket (~> 1.1)
323 | - FlipperKit (~> 0.54.0)
324 | - FlipperKit/Core (~> 0.54.0)
325 | - FlipperKit/CppBridge (~> 0.54.0)
326 | - FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0)
327 | - FlipperKit/FBDefines (~> 0.54.0)
328 | - FlipperKit/FKPortForwarding (~> 0.54.0)
329 | - FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0)
330 | - FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0)
331 | - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0)
332 | - FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0)
333 | - FlipperKit/FlipperKitReactPlugin (~> 0.54.0)
334 | - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0)
335 | - FlipperKit/SKIOSNetworkPlugin (~> 0.54.0)
336 | - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
337 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
338 | - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
339 | - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
340 | - React (from `../node_modules/react-native/`)
341 | - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
342 | - React-Core (from `../node_modules/react-native/`)
343 | - React-Core/DevSupport (from `../node_modules/react-native/`)
344 | - React-Core/RCTWebSocket (from `../node_modules/react-native/`)
345 | - React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
346 | - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
347 | - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
348 | - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
349 | - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
350 | - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
351 | - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
352 | - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
353 | - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
354 | - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
355 | - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
356 | - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
357 | - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
358 | - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
359 | - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
360 | - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
361 | - "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
362 | - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
363 | - RNReanimated (from `../node_modules/react-native-reanimated`)
364 | - RNScreens (from `../node_modules/react-native-screens`)
365 | - Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
366 |
367 | SPEC REPOS:
368 | trunk:
369 | - boost-for-react-native
370 | - CocoaAsyncSocket
371 | - CocoaLibEvent
372 | - Flipper
373 | - Flipper-DoubleConversion
374 | - Flipper-Folly
375 | - Flipper-Glog
376 | - Flipper-PeerTalk
377 | - Flipper-RSocket
378 | - FlipperKit
379 | - OpenSSL-Universal
380 | - YogaKit
381 |
382 | EXTERNAL SOURCES:
383 | DoubleConversion:
384 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
385 | FBLazyVector:
386 | :path: "../node_modules/react-native/Libraries/FBLazyVector"
387 | FBReactNativeSpec:
388 | :path: "../node_modules/react-native/Libraries/FBReactNativeSpec"
389 | Folly:
390 | :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
391 | glog:
392 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
393 | RCTRequired:
394 | :path: "../node_modules/react-native/Libraries/RCTRequired"
395 | RCTTypeSafety:
396 | :path: "../node_modules/react-native/Libraries/TypeSafety"
397 | React:
398 | :path: "../node_modules/react-native/"
399 | React-callinvoker:
400 | :path: "../node_modules/react-native/ReactCommon/callinvoker"
401 | React-Core:
402 | :path: "../node_modules/react-native/"
403 | React-CoreModules:
404 | :path: "../node_modules/react-native/React/CoreModules"
405 | React-cxxreact:
406 | :path: "../node_modules/react-native/ReactCommon/cxxreact"
407 | React-jsi:
408 | :path: "../node_modules/react-native/ReactCommon/jsi"
409 | React-jsiexecutor:
410 | :path: "../node_modules/react-native/ReactCommon/jsiexecutor"
411 | React-jsinspector:
412 | :path: "../node_modules/react-native/ReactCommon/jsinspector"
413 | react-native-safe-area-context:
414 | :path: "../node_modules/react-native-safe-area-context"
415 | React-RCTActionSheet:
416 | :path: "../node_modules/react-native/Libraries/ActionSheetIOS"
417 | React-RCTAnimation:
418 | :path: "../node_modules/react-native/Libraries/NativeAnimation"
419 | React-RCTBlob:
420 | :path: "../node_modules/react-native/Libraries/Blob"
421 | React-RCTImage:
422 | :path: "../node_modules/react-native/Libraries/Image"
423 | React-RCTLinking:
424 | :path: "../node_modules/react-native/Libraries/LinkingIOS"
425 | React-RCTNetwork:
426 | :path: "../node_modules/react-native/Libraries/Network"
427 | React-RCTSettings:
428 | :path: "../node_modules/react-native/Libraries/Settings"
429 | React-RCTText:
430 | :path: "../node_modules/react-native/Libraries/Text"
431 | React-RCTVibration:
432 | :path: "../node_modules/react-native/Libraries/Vibration"
433 | ReactCommon:
434 | :path: "../node_modules/react-native/ReactCommon"
435 | RNCMaskedView:
436 | :path: "../node_modules/@react-native-community/masked-view"
437 | RNGestureHandler:
438 | :path: "../node_modules/react-native-gesture-handler"
439 | RNReanimated:
440 | :path: "../node_modules/react-native-reanimated"
441 | RNScreens:
442 | :path: "../node_modules/react-native-screens"
443 | Yoga:
444 | :path: "../node_modules/react-native/ReactCommon/yoga"
445 |
446 | SPEC CHECKSUMS:
447 | boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
448 | CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
449 | CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
450 | DoubleConversion: cde416483dac037923206447da6e1454df403714
451 | FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
452 | FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
453 | Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
454 | Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
455 | Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a
456 | Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
457 | Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
458 | Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7
459 | FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d
460 | Folly: b73c3869541e86821df3c387eb0af5f65addfab4
461 | glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
462 | OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd
463 | RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
464 | RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
465 | React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
466 | React-callinvoker: c3f44dd3cb195b6aa46621fff95ded79d59043fe
467 | React-Core: d3b2a1ac9a2c13c3bcde712d9281fc1c8a5b315b
468 | React-CoreModules: 0581ff36cb797da0943d424f69e7098e43e9be60
469 | React-cxxreact: c1480d4fda5720086c90df537ee7d285d4c57ac3
470 | React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
471 | React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
472 | React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
473 | react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
474 | React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
475 | React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
476 | React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
477 | React-RCTImage: c1b1f2d3f43a4a528c8946d6092384b5c880d2f0
478 | React-RCTLinking: 35ae4ab9dc0410d1fcbdce4d7623194a27214fb2
479 | React-RCTNetwork: 29ec2696f8d8cfff7331fac83d3e893c95ef43ae
480 | React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a
481 | React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c
482 | React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
483 | ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
484 | RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f
485 | RNGestureHandler: 9b7e605a741412e20e13c512738a31bd1611759b
486 | RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
487 | RNScreens: 45c457af3d2ee9e08fc01e70da87e653d46b1198
488 | Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
489 | YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
490 |
491 | PODFILE CHECKSUM: 2ab1849c0e3b4924fdb6fbd82d60b9b2a42b4f75
492 |
493 | COCOAPODS: 1.10.0
494 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React Native Twilio Chat
5 |
6 |
7 | Build a Twilio-Powered Chat App Using React Native
8 |
9 | Quickly get started with a Twilio Programmable Chat
10 |
11 | Twilio Programmable Chat makes it easy for you to add chat features into your web and mobile apps without building or scaling a real-time chat backend. Chat has all the necessary APIs and features to integrate with your business logic to ensure you are in control.
12 |
13 | I wanted to build a quick, full-featured chat feature for my React Native app. I managed to do it with [Twilio Programmable Chat](https://www.twilio.com/docs/chat).
14 |
15 | I searched the internet a lot to find the best way to use Twilio Programmable Chat with React Native. Unfortunately, I couldn’t find much. So I decided to write an article about it, hopefully saving others some time.
16 |
17 | ## Setting up the Project
18 |
19 | Install the repository:
20 | ```sh
21 | git clone https://github.com/Gapur/react-native-twilio-chat.git
22 | ```
23 |
24 | After that, move it into the react-native-twilio-chat directory and run it from the terminal:
25 | ```
26 | cd react-native-twilio-chat
27 | npm run ios
28 | ```
29 |
30 | ## Creating Our Server
31 |
32 | Before we get started, We need to generate an access token to authorize the React Native app to communicate with the Programmable Twilio Chat.
33 | To set up our backend for Chat, we’ll need four values from our Twilio account. We’ll store these in our .env file:
34 | - Service instance SID—a service instance where all the data for our application is stored and scoped
35 | - Account SID — your primary Twilio account identifier
36 | - API key — used to authenticate
37 | - API secret — used to authenticate
38 |
39 | Now, if your account is ready, you can find your account SID on the [Twilio Console](https://www.twilio.com/console). You should copy and paste it as the value TWILIO_ACCOUNT_SID to the .env file.
40 |
41 |
42 |
43 |
44 |
45 | Next, We need to generate an API key and API secret by navigating to Settings > API Keys > New API Key.
46 |
47 |
48 |
49 |
50 |
51 | If you create these things successfully, let’s copy and paste the SID and secret as the values TWILIO_API_KEY and TWILIO_API_SECRET.
52 |
53 |
54 |
55 |
56 |
57 | Last, we need to create a new Chat Service by navigating to All Products & Services > Programmable Chat > Services > Chat Services.
58 |
59 |
60 |
61 |
62 |
63 | Let’s copy and paste the service SID as the value TWILIO_CHAT_SERVICE_SID.
64 |
65 | Finally, our .env file should look like this:
66 | ```js
67 | TWILIO_ACCOUNT_SID=your_account_sid
68 | TWILIO_API_KEY=your_api_key
69 | TWILIO_API_SECRET=your_api_secret
70 | TWILIO_CHAT_SERVICE_SID=your_chat_service_sid
71 | ```
72 |
73 | When our .env is ready, we can create a simple server with a single GET route, /token/:identity. This route will request and return a token from TWILIO. Let’s install dependencies for our server:
74 |
75 | ```sh
76 | yarn add express dotenv twilio
77 | ```
78 |
79 | Create our server.js:
80 | ```js
81 | require('dotenv').config();
82 |
83 | const Twilio = require('twilio');
84 | const express = require('express');
85 |
86 | const app = express();
87 |
88 | const AccessToken = Twilio.jwt.AccessToken;
89 | const ChatGrant = AccessToken.ChatGrant;
90 |
91 | app.get('/token/:identity', (req, res) => {
92 | const identity = req.params.identity;
93 | const token = new AccessToken(
94 | process.env.TWILIO_ACCOUNT_SID,
95 | process.env.TWILIO_API_KEY,
96 | process.env.TWILIO_API_SECRET,
97 | );
98 |
99 | token.identity = identity;
100 | token.addGrant(
101 | new ChatGrant({
102 | serviceSid: process.env.TWILIO_CHAT_SERVICE_SID,
103 | }),
104 | );
105 |
106 | res.send({
107 | identity: token.identity,
108 | jwt: token.toJwt(),
109 | });
110 | });
111 |
112 | app.listen(3001, function () {
113 | console.log('Programmable Chat server running on port 3001!');
114 | });
115 | ```
116 |
117 | That’s it for our server. Now, We can run our server with the following command line:
118 | ```sh
119 | node server.js
120 | ```
121 |
122 | ## React Native Navigation
123 |
124 | In order to show you the Twilio Programmable Chat in action, I’m going to build a full-featured app on React Native. Our app will have four screens: WelcomeScreen, ChatListScreen, ChatRoomScreen, and ChatCreateScreen.
125 |
126 | We need a router to navigate between screens in our React Native app. So I’m going to use the [react-native-navigation](https://github.com/wix/react-native-navigation) library. React Native Navigation provides 100% native-platform navigation on both iOS and Android. We should install it with the required packages:
127 |
128 | ```sh
129 | yarn add @react-navigation/native react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view @react-navigation/stack
130 | ```
131 |
132 | ## Welcome Screen
133 |
134 | We’ll start with the welcome screen. Let’s create welcome-screen.js and add the following code:
135 |
136 | ```js
137 | export function WelcomeScreen({ navigation }) {
138 | const [username, setUsername] = useState('');
139 |
140 | return (
141 |
142 |
143 | Welcome to Twilio Chat
144 |
151 | navigation.navigate(routes.ChatList.name, { username })}>
155 | Login
156 |
157 |
158 | );
159 | }
160 | ```
161 |
162 | We’ll use the username to generate the Twilio access token.
163 |
164 |
165 |
166 |
167 |
168 | ## Chat-Create Screen
169 |
170 | The next step is to create a chat client which is what we needed the token for. I’m going to use [twilio-chat](https://www.npmjs.com/package/twilio-chat) to connect and work with the [Twilio SDK](http://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/docs/index.html). Let’s install and test it:
171 |
172 | ```sh
173 | yarn add twilio-chat events
174 | ```
175 |
176 | Then, we’ll create a getToken method for handling communication with our token server.
177 |
178 | ```js
179 | const getToken = (username) =>
180 | axios.get(`http://localhost:3001/token/${username}`).then((twilioUser) => twilioUser.data.jwt);
181 | ```
182 |
183 | Now, we should create the Twilio Chat Client instance with a token by calling [create(token)](http://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/docs/Client.html#.create__anchor). Also, we have two events to help manage our token expiration: tokenAboutToExpire and tokenExpired.
184 |
185 | Let’s create a twilio-service.js file to prevent the repeat initializing of the Twilio Chat Client across all screens. We’ll create and store a single Twilio service client instance and use it on each screen.
186 |
187 | ```js
188 | import { Client } from 'twilio-chat';
189 |
190 | export class TwilioService {
191 | static serviceInstance;
192 | static chatClient;
193 |
194 | // create a single service instance
195 | static getInstance() {
196 | if (!TwilioService.serviceInstance) {
197 | TwilioService.serviceInstance = new TwilioService();
198 | }
199 | return TwilioService.serviceInstance;
200 | }
201 |
202 | // use chat client if don't have instance, create a new chat client
203 | async getChatClient(twilioToken) {
204 | if (!TwilioService.chatClient && !twilioToken) {
205 | throw new Error('Twilio token is null or undefined');
206 | }
207 | if (!TwilioService.chatClient && twilioToken) {
208 | return Client.create(twilioToken).then((client) => {
209 | TwilioService.chatClient = client;
210 | return TwilioService.chatClient;
211 | });
212 | }
213 | return Promise.resolve().then(() => TwilioService.chatClient);
214 | }
215 |
216 | // manage our token expiration
217 | addTokenListener(getToken) {
218 | if (!TwilioService.chatClient) {
219 | throw new Error('Twilio client is null or undefined');
220 | }
221 | TwilioService.chatClient.on('tokenAboutToExpire', () => {
222 | getToken().then(TwilioService.chatClient.updateToken);
223 | });
224 |
225 | TwilioService.chatClient.on('tokenExpired', () => {
226 | getToken().then(TwilioService.chatClient.updateToken);
227 | });
228 | return TwilioService.chatClient;
229 | }
230 |
231 | // gracefully shutting down library instance.
232 | clientShutdown() {
233 | TwilioService.chatClient?.shutdown();
234 | TwilioService.chatClient = null;
235 | }
236 | }
237 | ```
238 |
239 | Last, I’ll create chat-create-screen.js with the following code:
240 |
241 | ```js
242 | export function ChatCreateScreen() {
243 | const [channelName, setChannelName] = useState('');
244 | const [loading, setLoading] = useState(false);
245 |
246 | const onCreateOrJoin = () => {
247 | setLoading(true);
248 | TwilioService.getInstance()
249 | .getChatClient()
250 | .then((client) =>
251 | client
252 | .getChannelByUniqueName(channelName)
253 | .then((channel) => (channel.channelState.status !== 'joined' ? channel.join() : channel))
254 | .catch(() =>
255 | client.createChannel({ uniqueName: channelName, friendlyName: channelName }).then((channel) => channel.join()),
256 | ),
257 | )
258 | .then(() => showMessage({ message: 'You have joined.' }))
259 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
260 | .finally(() => setLoading(false));
261 | };
262 |
263 | return (
264 |
265 |
266 |
273 |
274 | Create Or Join
275 |
276 | {loading && }
277 |
278 | );
279 | }
280 | ```
281 |
282 | Once the chat client is initialized, we can create a new chat channel with [createChannel({ uniqueName, friendlyName })](http://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/docs/Client.html#createChannel__anchor) or join an existing channel with the join() method. To join an existing channel, we have to get the channel from Twilio by using the [getChannelByUniqueName()](http://media.twiliocdn.com/sdk/js/chat/releases/4.0.0/docs/Client.html#getChannelByUniqueName__anchor) method and passing the room name to it.
283 |
284 | If the channel doesn’t exist, an exception will be thrown. If it does exist, the method will return the channel resource, and from there, the channel can be joined.
285 |
286 |
287 |
288 |
289 |
290 | ## Chat List Screen
291 |
292 | I’m going to show all of my subscribed channels on the ChatListScreen. As a user, I want to work with updated channels when I join or create a new channel on the CreateChannelScreen. Therefore, we need to store channels globally in Redux or React Context. Redux is too complicated for our simple app, so we’ll use React Context.
293 |
294 | Let’s create our app-context.js with the following code:
295 |
296 | ```js
297 | import React, { useState, useContext, createContext } from 'react';
298 |
299 | const defaultInitialState = { channels: [], updateChannels: () => {} };
300 |
301 | const AppContext = createContext(defaultInitialState);
302 |
303 | export function useApp() {
304 | return useContext(AppContext);
305 | }
306 |
307 | export function AppProvider({ children }) {
308 | const [channels, setChannels] = useState([]);
309 |
310 | return {children} ;
311 | }
312 | ```
313 |
314 | AppContext stores a list of channels and the updateChannels method. Hence we can get all of the channels:
315 |
316 | ```sh
317 | const { channels, updateChannels } = useApp();
318 | ```
319 |
320 | Now, our chat-list-screen.js:
321 |
322 | ```js
323 | export function ChatListScreen({ navigation, route }) {
324 | const { username } = route.params;
325 | const { channels, updateChannels } = useApp();
326 | const channelPaginator = useRef();
327 |
328 | useLayoutEffect(() => {
329 | navigation.setOptions({
330 | headerRight: () => (
331 | navigation.navigate(routes.ChatCreat.name)}>
332 | +
333 |
334 | ),
335 | });
336 | }, [navigation]);
337 |
338 | const setChannelEvents = useCallback(
339 | (client) => {
340 | client.on('messageAdded', (message) => {
341 | updateChannels((prevChannels) =>
342 | prevChannels.map((channel) =>
343 | channel.id === message.channel.sid ? { ...channel, lastMessageTime: message.dateCreated } : channel,
344 | ),
345 | );
346 | });
347 | return client;
348 | },
349 | [updateChannels],
350 | );
351 |
352 | const getSubscribedChannels = useCallback(
353 | (client) =>
354 | client.getSubscribedChannels().then((paginator) => {
355 | channelPaginator.current = paginator;
356 | const newChannels = TwilioService.getInstance().parseChannels(channelPaginator.current.items);
357 | updateChannels(newChannels);
358 | }),
359 | [updateChannels],
360 | );
361 |
362 | useEffect(() => {
363 | getToken(username)
364 | .then((token) => TwilioService.getInstance().getChatClient(token))
365 | .then(() => TwilioService.getInstance().addTokenListener(getToken))
366 | .then(setChannelEvents)
367 | .then(getSubscribedChannels)
368 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
369 | .finally(() => setLoading(false));
370 |
371 | return () => TwilioService.getInstance().clientShutdown();
372 | }, [username, setChannelEvents, getSubscribedChannels]);
373 |
374 | return (
375 |
376 | item.id}
379 | renderItem={({ item }) => (
380 | navigation.navigate(routes.ChatRoom.name, { channelId: item.id, identity: username })}
383 | />
384 | )}
385 | />
386 |
387 | );
388 | }
389 | ```
390 |
391 | First, we retrieve the token and create an instance of the Twilio Chat client. Then, we get the current list of all of our subscribed channels by using the getSubscribedChannels() method and storing them in the global React Context.
392 |
393 | Twilio doesn’t give you the feature to sort the channel list based on a most recent message. Your best bet is loading all of the channels into an array and sorting them yourself.
394 |
395 | Therefore I subscribed to the messageAdded event, which fires when a new message has been added to the channel on the server because I want to sort the channel list by the last-message time. So when someone messages via the chat, we’ll update the last-message time of the specific channel.
396 |
397 |
398 |
399 |
400 |
401 | ## Chat Room Screen
402 |
403 | I’m going to use [react-native-gifted-chat](https://github.com/FaridSafi/react-native-gifted-chat) for creating a chat room of the channel. react-native-gifted-chat is the most complete and easy-to-use chat UI for React Native.
404 |
405 | Let’s install it:
406 |
407 | ```sh
408 | yarn add react-native-gifted-chat
409 | ```
410 |
411 | First we have to get a Twilio Chat client or create one if one doesn’t exist. Then we need to get the specific channel using getChannelBySid(channelSid).
412 |
413 | If we get the channel, we can get all of the messages from the channel by using the getMessages() method.
414 |
415 | Also, I’ll subscribe to the messageAdded event, which fires when a new message has been added to the channel and updates our chat.
416 |
417 | Let’s create chat-room-screen.js:
418 |
419 | ```js
420 | export function ChatRoomScreen({ route }) {
421 | const { channelId, identity } = route.params;
422 | const [messages, setMessages] = useState([]);
423 | const chatClientChannel = useRef();
424 | const chatMessagesPaginator = useRef();
425 |
426 | const setChannelEvents = useCallback((channel) => {
427 | chatClientChannel.current = channel;
428 | chatClientChannel.current.on('messageAdded', (message) => {
429 | const newMessage = TwilioService.getInstance().parseMessage(message);
430 | const { giftedId } = message.attributes;
431 | if (giftedId) {
432 | setMessages((prevMessages) => prevMessages.map((m) => (m._id === giftedId ? newMessage : m)));
433 | } else {
434 | setMessages((prevMessages) => [newMessage, ...prevMessages]);
435 | }
436 | });
437 | return chatClientChannel.current;
438 | }, []);
439 |
440 | useEffect(() => {
441 | TwilioService.getInstance()
442 | .getChatClient()
443 | .then((client) => client.getChannelBySid(channelId))
444 | .then((channel) => setChannelEvents(channel))
445 | .then((currentChannel) => currentChannel.getMessages())
446 | .then((paginator) => {
447 | chatMessagesPaginator.current = paginator;
448 | const newMessages = TwilioService.getInstance().parseMessages(paginator.items);
449 | setMessages(newMessages);
450 | })
451 | .catch((err) => showMessage({ message: err.message, type: 'danger' }))
452 | }, [channelId, setChannelEvents]);
453 |
454 | const onSend = useCallback((newMessages = []) => {
455 | const attributes = { giftedId: newMessages[0]._id };
456 | setMessages((prevMessages) => GiftedChat.append(prevMessages, newMessages));
457 | chatClientChannel.current?.sendMessage(newMessages[0].text, attributes);
458 | }, []);
459 |
460 | return (
461 |
462 | onSend(messages)}
467 | user={{ _id: identity }}
468 | />
469 |
470 | );
471 | }
472 | ```
473 |
474 | I created a method called onSend(). This method will call the SDK method sendMessage() on the channel object and pass the message typed by your user to it.
475 |
476 |
477 |
478 |
479 |
480 |
481 | ## Let’s Demo Our Twilio Chat App
482 |
483 |
484 |
485 |
486 |
487 | ## Article on Medium
488 |
489 | [Build a Twilio-Powered Chat App Using React Native](https://medium.com/better-programming/build-a-twilio-powered-chat-app-using-reactn-ative-2460b7995a30)
490 |
491 | ## How to contribute?
492 |
493 | 1. Fork this repo
494 | 2. Clone your fork
495 | 3. Code 🤓
496 | 4. Test your changes
497 | 5. Submit a PR!
498 |
--------------------------------------------------------------------------------
/ios/react_native_twilio_chat.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 00E356F31AD99517003FC87E /* react_native_twilio_chatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* react_native_twilio_chatTests.m */; };
11 | 041CDF1F21E05791DB72349D /* libPods-react_native_twilio_chat-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A462B7A4A4BA061847281A9 /* libPods-react_native_twilio_chat-tvOSTests.a */; };
12 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
14 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
15 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
16 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
17 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
18 | 2DCD954D1E0B4F2C00145EB5 /* react_native_twilio_chatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* react_native_twilio_chatTests.m */; };
19 | 444C270637195F3079AECFD8 /* libPods-react_native_twilio_chat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 404B57059D9C26423413E348 /* libPods-react_native_twilio_chat.a */; };
20 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
21 | EA0A24CC8B11468CAE21767E /* libPods-react_native_twilio_chat-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC27D0EDA7E3E12EEEDD10D9 /* libPods-react_native_twilio_chat-tvOS.a */; };
22 | F3EBC40295CF69D309D91753 /* libPods-react_native_twilio_chat-react_native_twilio_chatTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F9B89AAE192B32517C0BF21B /* libPods-react_native_twilio_chat-react_native_twilio_chatTests.a */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXContainerItemProxy section */
26 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
27 | isa = PBXContainerItemProxy;
28 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
29 | proxyType = 1;
30 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
31 | remoteInfo = react_native_twilio_chat;
32 | };
33 | 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = {
34 | isa = PBXContainerItemProxy;
35 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
36 | proxyType = 1;
37 | remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
38 | remoteInfo = "react_native_twilio_chat-tvOS";
39 | };
40 | /* End PBXContainerItemProxy section */
41 |
42 | /* Begin PBXFileReference section */
43 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
44 | 00E356EE1AD99517003FC87E /* react_native_twilio_chatTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = react_native_twilio_chatTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
45 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
46 | 00E356F21AD99517003FC87E /* react_native_twilio_chatTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = react_native_twilio_chatTests.m; sourceTree = ""; };
47 | 058B2C5015276964FC513EAE /* Pods-react_native_twilio_chat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat.debug.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat/Pods-react_native_twilio_chat.debug.xcconfig"; sourceTree = ""; };
48 | 0A3466B50B100C16DB4763DC /* Pods-react_native_twilio_chat-tvOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-tvOSTests.debug.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-tvOSTests/Pods-react_native_twilio_chat-tvOSTests.debug.xcconfig"; sourceTree = ""; };
49 | 13B07F961A680F5B00A75B9A /* react_native_twilio_chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = react_native_twilio_chat.app; sourceTree = BUILT_PRODUCTS_DIR; };
50 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = react_native_twilio_chat/AppDelegate.h; sourceTree = ""; };
51 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = react_native_twilio_chat/AppDelegate.m; sourceTree = ""; };
52 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = react_native_twilio_chat/Images.xcassets; sourceTree = ""; };
53 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = react_native_twilio_chat/Info.plist; sourceTree = ""; };
54 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = react_native_twilio_chat/main.m; sourceTree = ""; };
55 | 25B61C65E38147E2CC328D2A /* Pods-react_native_twilio_chat-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-tvOSTests/Pods-react_native_twilio_chat-tvOSTests.release.xcconfig"; sourceTree = ""; };
56 | 2A462B7A4A4BA061847281A9 /* libPods-react_native_twilio_chat-tvOSTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-react_native_twilio_chat-tvOSTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 2D02E47B1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "react_native_twilio_chat-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 2D02E4901E0B4A5D006451C7 /* react_native_twilio_chat-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "react_native_twilio_chat-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
59 | 404B57059D9C26423413E348 /* libPods-react_native_twilio_chat.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-react_native_twilio_chat.a"; sourceTree = BUILT_PRODUCTS_DIR; };
60 | 515793399CA1CC6D6CDF1997 /* Pods-react_native_twilio_chat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat.release.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat/Pods-react_native_twilio_chat.release.xcconfig"; sourceTree = ""; };
61 | 7D4CDBA6C841D07DB1E9DC66 /* Pods-react_native_twilio_chat-tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-tvOS.release.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-tvOS/Pods-react_native_twilio_chat-tvOS.release.xcconfig"; sourceTree = ""; };
62 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = react_native_twilio_chat/LaunchScreen.storyboard; sourceTree = ""; };
63 | 8EEA9AB15C13BA4334197DB9 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-react_native_twilio_chatTests.debug.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-react_native_twilio_chatTests/Pods-react_native_twilio_chat-react_native_twilio_chatTests.debug.xcconfig"; sourceTree = ""; };
64 | A841F9AA914FC2A277D301DA /* Pods-react_native_twilio_chat-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-tvOS.debug.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-tvOS/Pods-react_native_twilio_chat-tvOS.debug.xcconfig"; sourceTree = ""; };
65 | B5B178859465532CDE5561D4 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-react_native_twilio_chat-react_native_twilio_chatTests.release.xcconfig"; path = "Target Support Files/Pods-react_native_twilio_chat-react_native_twilio_chatTests/Pods-react_native_twilio_chat-react_native_twilio_chatTests.release.xcconfig"; sourceTree = ""; };
66 | DC27D0EDA7E3E12EEEDD10D9 /* libPods-react_native_twilio_chat-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-react_native_twilio_chat-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
67 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
68 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
69 | F9B89AAE192B32517C0BF21B /* libPods-react_native_twilio_chat-react_native_twilio_chatTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-react_native_twilio_chat-react_native_twilio_chatTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
70 | /* End PBXFileReference section */
71 |
72 | /* Begin PBXFrameworksBuildPhase section */
73 | 00E356EB1AD99517003FC87E /* Frameworks */ = {
74 | isa = PBXFrameworksBuildPhase;
75 | buildActionMask = 2147483647;
76 | files = (
77 | F3EBC40295CF69D309D91753 /* libPods-react_native_twilio_chat-react_native_twilio_chatTests.a in Frameworks */,
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | 444C270637195F3079AECFD8 /* libPods-react_native_twilio_chat.a in Frameworks */,
86 | );
87 | runOnlyForDeploymentPostprocessing = 0;
88 | };
89 | 2D02E4781E0B4A5D006451C7 /* Frameworks */ = {
90 | isa = PBXFrameworksBuildPhase;
91 | buildActionMask = 2147483647;
92 | files = (
93 | EA0A24CC8B11468CAE21767E /* libPods-react_native_twilio_chat-tvOS.a in Frameworks */,
94 | );
95 | runOnlyForDeploymentPostprocessing = 0;
96 | };
97 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = {
98 | isa = PBXFrameworksBuildPhase;
99 | buildActionMask = 2147483647;
100 | files = (
101 | 041CDF1F21E05791DB72349D /* libPods-react_native_twilio_chat-tvOSTests.a in Frameworks */,
102 | );
103 | runOnlyForDeploymentPostprocessing = 0;
104 | };
105 | /* End PBXFrameworksBuildPhase section */
106 |
107 | /* Begin PBXGroup section */
108 | 00E356EF1AD99517003FC87E /* react_native_twilio_chatTests */ = {
109 | isa = PBXGroup;
110 | children = (
111 | 00E356F21AD99517003FC87E /* react_native_twilio_chatTests.m */,
112 | 00E356F01AD99517003FC87E /* Supporting Files */,
113 | );
114 | path = react_native_twilio_chatTests;
115 | sourceTree = "";
116 | };
117 | 00E356F01AD99517003FC87E /* Supporting Files */ = {
118 | isa = PBXGroup;
119 | children = (
120 | 00E356F11AD99517003FC87E /* Info.plist */,
121 | );
122 | name = "Supporting Files";
123 | sourceTree = "";
124 | };
125 | 13B07FAE1A68108700A75B9A /* react_native_twilio_chat */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */,
129 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
130 | 13B07FB01A68108700A75B9A /* AppDelegate.m */,
131 | 13B07FB51A68108700A75B9A /* Images.xcassets */,
132 | 13B07FB61A68108700A75B9A /* Info.plist */,
133 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
134 | 13B07FB71A68108700A75B9A /* main.m */,
135 | );
136 | name = react_native_twilio_chat;
137 | sourceTree = "";
138 | };
139 | 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
140 | isa = PBXGroup;
141 | children = (
142 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
143 | ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
144 | 404B57059D9C26423413E348 /* libPods-react_native_twilio_chat.a */,
145 | F9B89AAE192B32517C0BF21B /* libPods-react_native_twilio_chat-react_native_twilio_chatTests.a */,
146 | DC27D0EDA7E3E12EEEDD10D9 /* libPods-react_native_twilio_chat-tvOS.a */,
147 | 2A462B7A4A4BA061847281A9 /* libPods-react_native_twilio_chat-tvOSTests.a */,
148 | );
149 | name = Frameworks;
150 | sourceTree = "";
151 | };
152 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
153 | isa = PBXGroup;
154 | children = (
155 | );
156 | name = Libraries;
157 | sourceTree = "";
158 | };
159 | 83CBB9F61A601CBA00E9B192 = {
160 | isa = PBXGroup;
161 | children = (
162 | 13B07FAE1A68108700A75B9A /* react_native_twilio_chat */,
163 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
164 | 00E356EF1AD99517003FC87E /* react_native_twilio_chatTests */,
165 | 83CBBA001A601CBA00E9B192 /* Products */,
166 | 2D16E6871FA4F8E400B85C8A /* Frameworks */,
167 | 8A1A31B87A98E464B11C75C8 /* Pods */,
168 | );
169 | indentWidth = 2;
170 | sourceTree = "";
171 | tabWidth = 2;
172 | usesTabs = 0;
173 | };
174 | 83CBBA001A601CBA00E9B192 /* Products */ = {
175 | isa = PBXGroup;
176 | children = (
177 | 13B07F961A680F5B00A75B9A /* react_native_twilio_chat.app */,
178 | 00E356EE1AD99517003FC87E /* react_native_twilio_chatTests.xctest */,
179 | 2D02E47B1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS.app */,
180 | 2D02E4901E0B4A5D006451C7 /* react_native_twilio_chat-tvOSTests.xctest */,
181 | );
182 | name = Products;
183 | sourceTree = "";
184 | };
185 | 8A1A31B87A98E464B11C75C8 /* Pods */ = {
186 | isa = PBXGroup;
187 | children = (
188 | 058B2C5015276964FC513EAE /* Pods-react_native_twilio_chat.debug.xcconfig */,
189 | 515793399CA1CC6D6CDF1997 /* Pods-react_native_twilio_chat.release.xcconfig */,
190 | 8EEA9AB15C13BA4334197DB9 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.debug.xcconfig */,
191 | B5B178859465532CDE5561D4 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.release.xcconfig */,
192 | A841F9AA914FC2A277D301DA /* Pods-react_native_twilio_chat-tvOS.debug.xcconfig */,
193 | 7D4CDBA6C841D07DB1E9DC66 /* Pods-react_native_twilio_chat-tvOS.release.xcconfig */,
194 | 0A3466B50B100C16DB4763DC /* Pods-react_native_twilio_chat-tvOSTests.debug.xcconfig */,
195 | 25B61C65E38147E2CC328D2A /* Pods-react_native_twilio_chat-tvOSTests.release.xcconfig */,
196 | );
197 | name = Pods;
198 | path = Pods;
199 | sourceTree = "";
200 | };
201 | /* End PBXGroup section */
202 |
203 | /* Begin PBXNativeTarget section */
204 | 00E356ED1AD99517003FC87E /* react_native_twilio_chatTests */ = {
205 | isa = PBXNativeTarget;
206 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "react_native_twilio_chatTests" */;
207 | buildPhases = (
208 | 4A396DDEEC92CC1F51E0C2E1 /* [CP] Check Pods Manifest.lock */,
209 | 00E356EA1AD99517003FC87E /* Sources */,
210 | 00E356EB1AD99517003FC87E /* Frameworks */,
211 | 00E356EC1AD99517003FC87E /* Resources */,
212 | B4588C20AEA958BE49FB9A83 /* [CP] Copy Pods Resources */,
213 | );
214 | buildRules = (
215 | );
216 | dependencies = (
217 | 00E356F51AD99517003FC87E /* PBXTargetDependency */,
218 | );
219 | name = react_native_twilio_chatTests;
220 | productName = react_native_twilio_chatTests;
221 | productReference = 00E356EE1AD99517003FC87E /* react_native_twilio_chatTests.xctest */;
222 | productType = "com.apple.product-type.bundle.unit-test";
223 | };
224 | 13B07F861A680F5B00A75B9A /* react_native_twilio_chat */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "react_native_twilio_chat" */;
227 | buildPhases = (
228 | 60A8E55B58C076708F9F39E4 /* [CP] Check Pods Manifest.lock */,
229 | FD10A7F022414F080027D42C /* Start Packager */,
230 | 13B07F871A680F5B00A75B9A /* Sources */,
231 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
232 | 13B07F8E1A680F5B00A75B9A /* Resources */,
233 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
234 | 8672D912C5D804CCEF236521 /* [CP] Copy Pods Resources */,
235 | );
236 | buildRules = (
237 | );
238 | dependencies = (
239 | );
240 | name = react_native_twilio_chat;
241 | productName = react_native_twilio_chat;
242 | productReference = 13B07F961A680F5B00A75B9A /* react_native_twilio_chat.app */;
243 | productType = "com.apple.product-type.application";
244 | };
245 | 2D02E47A1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS */ = {
246 | isa = PBXNativeTarget;
247 | buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "react_native_twilio_chat-tvOS" */;
248 | buildPhases = (
249 | A682B571EAAAE002BC2F5D58 /* [CP] Check Pods Manifest.lock */,
250 | FD10A7F122414F3F0027D42C /* Start Packager */,
251 | 2D02E4771E0B4A5D006451C7 /* Sources */,
252 | 2D02E4781E0B4A5D006451C7 /* Frameworks */,
253 | 2D02E4791E0B4A5D006451C7 /* Resources */,
254 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,
255 | );
256 | buildRules = (
257 | );
258 | dependencies = (
259 | );
260 | name = "react_native_twilio_chat-tvOS";
261 | productName = "react_native_twilio_chat-tvOS";
262 | productReference = 2D02E47B1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS.app */;
263 | productType = "com.apple.product-type.application";
264 | };
265 | 2D02E48F1E0B4A5D006451C7 /* react_native_twilio_chat-tvOSTests */ = {
266 | isa = PBXNativeTarget;
267 | buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "react_native_twilio_chat-tvOSTests" */;
268 | buildPhases = (
269 | B036A81E07245B8E111A356F /* [CP] Check Pods Manifest.lock */,
270 | 2D02E48C1E0B4A5D006451C7 /* Sources */,
271 | 2D02E48D1E0B4A5D006451C7 /* Frameworks */,
272 | 2D02E48E1E0B4A5D006451C7 /* Resources */,
273 | );
274 | buildRules = (
275 | );
276 | dependencies = (
277 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
278 | );
279 | name = "react_native_twilio_chat-tvOSTests";
280 | productName = "react_native_twilio_chat-tvOSTests";
281 | productReference = 2D02E4901E0B4A5D006451C7 /* react_native_twilio_chat-tvOSTests.xctest */;
282 | productType = "com.apple.product-type.bundle.unit-test";
283 | };
284 | /* End PBXNativeTarget section */
285 |
286 | /* Begin PBXProject section */
287 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
288 | isa = PBXProject;
289 | attributes = {
290 | LastUpgradeCheck = 1130;
291 | TargetAttributes = {
292 | 00E356ED1AD99517003FC87E = {
293 | CreatedOnToolsVersion = 6.2;
294 | TestTargetID = 13B07F861A680F5B00A75B9A;
295 | };
296 | 13B07F861A680F5B00A75B9A = {
297 | LastSwiftMigration = 1120;
298 | };
299 | 2D02E47A1E0B4A5D006451C7 = {
300 | CreatedOnToolsVersion = 8.2.1;
301 | ProvisioningStyle = Automatic;
302 | };
303 | 2D02E48F1E0B4A5D006451C7 = {
304 | CreatedOnToolsVersion = 8.2.1;
305 | ProvisioningStyle = Automatic;
306 | TestTargetID = 2D02E47A1E0B4A5D006451C7;
307 | };
308 | };
309 | };
310 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "react_native_twilio_chat" */;
311 | compatibilityVersion = "Xcode 3.2";
312 | developmentRegion = en;
313 | hasScannedForEncodings = 0;
314 | knownRegions = (
315 | en,
316 | Base,
317 | );
318 | mainGroup = 83CBB9F61A601CBA00E9B192;
319 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
320 | projectDirPath = "";
321 | projectRoot = "";
322 | targets = (
323 | 13B07F861A680F5B00A75B9A /* react_native_twilio_chat */,
324 | 00E356ED1AD99517003FC87E /* react_native_twilio_chatTests */,
325 | 2D02E47A1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS */,
326 | 2D02E48F1E0B4A5D006451C7 /* react_native_twilio_chat-tvOSTests */,
327 | );
328 | };
329 | /* End PBXProject section */
330 |
331 | /* Begin PBXResourcesBuildPhase section */
332 | 00E356EC1AD99517003FC87E /* Resources */ = {
333 | isa = PBXResourcesBuildPhase;
334 | buildActionMask = 2147483647;
335 | files = (
336 | );
337 | runOnlyForDeploymentPostprocessing = 0;
338 | };
339 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
340 | isa = PBXResourcesBuildPhase;
341 | buildActionMask = 2147483647;
342 | files = (
343 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
344 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
345 | );
346 | runOnlyForDeploymentPostprocessing = 0;
347 | };
348 | 2D02E4791E0B4A5D006451C7 /* Resources */ = {
349 | isa = PBXResourcesBuildPhase;
350 | buildActionMask = 2147483647;
351 | files = (
352 | 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */,
353 | );
354 | runOnlyForDeploymentPostprocessing = 0;
355 | };
356 | 2D02E48E1E0B4A5D006451C7 /* Resources */ = {
357 | isa = PBXResourcesBuildPhase;
358 | buildActionMask = 2147483647;
359 | files = (
360 | );
361 | runOnlyForDeploymentPostprocessing = 0;
362 | };
363 | /* End PBXResourcesBuildPhase section */
364 |
365 | /* Begin PBXShellScriptBuildPhase section */
366 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
367 | isa = PBXShellScriptBuildPhase;
368 | buildActionMask = 2147483647;
369 | files = (
370 | );
371 | inputPaths = (
372 | );
373 | name = "Bundle React Native code and images";
374 | outputPaths = (
375 | );
376 | runOnlyForDeploymentPostprocessing = 0;
377 | shellPath = /bin/sh;
378 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
379 | };
380 | 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
381 | isa = PBXShellScriptBuildPhase;
382 | buildActionMask = 2147483647;
383 | files = (
384 | );
385 | inputPaths = (
386 | );
387 | name = "Bundle React Native Code And Images";
388 | outputPaths = (
389 | );
390 | runOnlyForDeploymentPostprocessing = 0;
391 | shellPath = /bin/sh;
392 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh";
393 | };
394 | 4A396DDEEC92CC1F51E0C2E1 /* [CP] Check Pods Manifest.lock */ = {
395 | isa = PBXShellScriptBuildPhase;
396 | buildActionMask = 2147483647;
397 | files = (
398 | );
399 | inputFileListPaths = (
400 | );
401 | inputPaths = (
402 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
403 | "${PODS_ROOT}/Manifest.lock",
404 | );
405 | name = "[CP] Check Pods Manifest.lock";
406 | outputFileListPaths = (
407 | );
408 | outputPaths = (
409 | "$(DERIVED_FILE_DIR)/Pods-react_native_twilio_chat-react_native_twilio_chatTests-checkManifestLockResult.txt",
410 | );
411 | runOnlyForDeploymentPostprocessing = 0;
412 | shellPath = /bin/sh;
413 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
414 | showEnvVarsInLog = 0;
415 | };
416 | 60A8E55B58C076708F9F39E4 /* [CP] Check Pods Manifest.lock */ = {
417 | isa = PBXShellScriptBuildPhase;
418 | buildActionMask = 2147483647;
419 | files = (
420 | );
421 | inputFileListPaths = (
422 | );
423 | inputPaths = (
424 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
425 | "${PODS_ROOT}/Manifest.lock",
426 | );
427 | name = "[CP] Check Pods Manifest.lock";
428 | outputFileListPaths = (
429 | );
430 | outputPaths = (
431 | "$(DERIVED_FILE_DIR)/Pods-react_native_twilio_chat-checkManifestLockResult.txt",
432 | );
433 | runOnlyForDeploymentPostprocessing = 0;
434 | shellPath = /bin/sh;
435 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
436 | showEnvVarsInLog = 0;
437 | };
438 | 8672D912C5D804CCEF236521 /* [CP] Copy Pods Resources */ = {
439 | isa = PBXShellScriptBuildPhase;
440 | buildActionMask = 2147483647;
441 | files = (
442 | );
443 | inputPaths = (
444 | "${PODS_ROOT}/Target Support Files/Pods-react_native_twilio_chat/Pods-react_native_twilio_chat-resources.sh",
445 | "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
446 | );
447 | name = "[CP] Copy Pods Resources";
448 | outputPaths = (
449 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
450 | );
451 | runOnlyForDeploymentPostprocessing = 0;
452 | shellPath = /bin/sh;
453 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-react_native_twilio_chat/Pods-react_native_twilio_chat-resources.sh\"\n";
454 | showEnvVarsInLog = 0;
455 | };
456 | A682B571EAAAE002BC2F5D58 /* [CP] Check Pods Manifest.lock */ = {
457 | isa = PBXShellScriptBuildPhase;
458 | buildActionMask = 2147483647;
459 | files = (
460 | );
461 | inputFileListPaths = (
462 | );
463 | inputPaths = (
464 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
465 | "${PODS_ROOT}/Manifest.lock",
466 | );
467 | name = "[CP] Check Pods Manifest.lock";
468 | outputFileListPaths = (
469 | );
470 | outputPaths = (
471 | "$(DERIVED_FILE_DIR)/Pods-react_native_twilio_chat-tvOS-checkManifestLockResult.txt",
472 | );
473 | runOnlyForDeploymentPostprocessing = 0;
474 | shellPath = /bin/sh;
475 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
476 | showEnvVarsInLog = 0;
477 | };
478 | B036A81E07245B8E111A356F /* [CP] Check Pods Manifest.lock */ = {
479 | isa = PBXShellScriptBuildPhase;
480 | buildActionMask = 2147483647;
481 | files = (
482 | );
483 | inputFileListPaths = (
484 | );
485 | inputPaths = (
486 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
487 | "${PODS_ROOT}/Manifest.lock",
488 | );
489 | name = "[CP] Check Pods Manifest.lock";
490 | outputFileListPaths = (
491 | );
492 | outputPaths = (
493 | "$(DERIVED_FILE_DIR)/Pods-react_native_twilio_chat-tvOSTests-checkManifestLockResult.txt",
494 | );
495 | runOnlyForDeploymentPostprocessing = 0;
496 | shellPath = /bin/sh;
497 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
498 | showEnvVarsInLog = 0;
499 | };
500 | B4588C20AEA958BE49FB9A83 /* [CP] Copy Pods Resources */ = {
501 | isa = PBXShellScriptBuildPhase;
502 | buildActionMask = 2147483647;
503 | files = (
504 | );
505 | inputPaths = (
506 | "${PODS_ROOT}/Target Support Files/Pods-react_native_twilio_chat-react_native_twilio_chatTests/Pods-react_native_twilio_chat-react_native_twilio_chatTests-resources.sh",
507 | "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
508 | );
509 | name = "[CP] Copy Pods Resources";
510 | outputPaths = (
511 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
512 | );
513 | runOnlyForDeploymentPostprocessing = 0;
514 | shellPath = /bin/sh;
515 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-react_native_twilio_chat-react_native_twilio_chatTests/Pods-react_native_twilio_chat-react_native_twilio_chatTests-resources.sh\"\n";
516 | showEnvVarsInLog = 0;
517 | };
518 | FD10A7F022414F080027D42C /* Start Packager */ = {
519 | isa = PBXShellScriptBuildPhase;
520 | buildActionMask = 2147483647;
521 | files = (
522 | );
523 | inputFileListPaths = (
524 | );
525 | inputPaths = (
526 | );
527 | name = "Start Packager";
528 | outputFileListPaths = (
529 | );
530 | outputPaths = (
531 | );
532 | runOnlyForDeploymentPostprocessing = 0;
533 | shellPath = /bin/sh;
534 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
535 | showEnvVarsInLog = 0;
536 | };
537 | FD10A7F122414F3F0027D42C /* Start Packager */ = {
538 | isa = PBXShellScriptBuildPhase;
539 | buildActionMask = 2147483647;
540 | files = (
541 | );
542 | inputFileListPaths = (
543 | );
544 | inputPaths = (
545 | );
546 | name = "Start Packager";
547 | outputFileListPaths = (
548 | );
549 | outputPaths = (
550 | );
551 | runOnlyForDeploymentPostprocessing = 0;
552 | shellPath = /bin/sh;
553 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
554 | showEnvVarsInLog = 0;
555 | };
556 | /* End PBXShellScriptBuildPhase section */
557 |
558 | /* Begin PBXSourcesBuildPhase section */
559 | 00E356EA1AD99517003FC87E /* Sources */ = {
560 | isa = PBXSourcesBuildPhase;
561 | buildActionMask = 2147483647;
562 | files = (
563 | 00E356F31AD99517003FC87E /* react_native_twilio_chatTests.m in Sources */,
564 | );
565 | runOnlyForDeploymentPostprocessing = 0;
566 | };
567 | 13B07F871A680F5B00A75B9A /* Sources */ = {
568 | isa = PBXSourcesBuildPhase;
569 | buildActionMask = 2147483647;
570 | files = (
571 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
572 | 13B07FC11A68108700A75B9A /* main.m in Sources */,
573 | );
574 | runOnlyForDeploymentPostprocessing = 0;
575 | };
576 | 2D02E4771E0B4A5D006451C7 /* Sources */ = {
577 | isa = PBXSourcesBuildPhase;
578 | buildActionMask = 2147483647;
579 | files = (
580 | 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */,
581 | 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */,
582 | );
583 | runOnlyForDeploymentPostprocessing = 0;
584 | };
585 | 2D02E48C1E0B4A5D006451C7 /* Sources */ = {
586 | isa = PBXSourcesBuildPhase;
587 | buildActionMask = 2147483647;
588 | files = (
589 | 2DCD954D1E0B4F2C00145EB5 /* react_native_twilio_chatTests.m in Sources */,
590 | );
591 | runOnlyForDeploymentPostprocessing = 0;
592 | };
593 | /* End PBXSourcesBuildPhase section */
594 |
595 | /* Begin PBXTargetDependency section */
596 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
597 | isa = PBXTargetDependency;
598 | target = 13B07F861A680F5B00A75B9A /* react_native_twilio_chat */;
599 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
600 | };
601 | 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
602 | isa = PBXTargetDependency;
603 | target = 2D02E47A1E0B4A5D006451C7 /* react_native_twilio_chat-tvOS */;
604 | targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
605 | };
606 | /* End PBXTargetDependency section */
607 |
608 | /* Begin XCBuildConfiguration section */
609 | 00E356F61AD99517003FC87E /* Debug */ = {
610 | isa = XCBuildConfiguration;
611 | baseConfigurationReference = 8EEA9AB15C13BA4334197DB9 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.debug.xcconfig */;
612 | buildSettings = {
613 | BUNDLE_LOADER = "$(TEST_HOST)";
614 | GCC_PREPROCESSOR_DEFINITIONS = (
615 | "DEBUG=1",
616 | "$(inherited)",
617 | );
618 | INFOPLIST_FILE = react_native_twilio_chatTests/Info.plist;
619 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
620 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
621 | OTHER_LDFLAGS = (
622 | "-ObjC",
623 | "-lc++",
624 | "$(inherited)",
625 | );
626 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
627 | PRODUCT_NAME = "$(TARGET_NAME)";
628 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/react_native_twilio_chat.app/react_native_twilio_chat";
629 | };
630 | name = Debug;
631 | };
632 | 00E356F71AD99517003FC87E /* Release */ = {
633 | isa = XCBuildConfiguration;
634 | baseConfigurationReference = B5B178859465532CDE5561D4 /* Pods-react_native_twilio_chat-react_native_twilio_chatTests.release.xcconfig */;
635 | buildSettings = {
636 | BUNDLE_LOADER = "$(TEST_HOST)";
637 | COPY_PHASE_STRIP = NO;
638 | INFOPLIST_FILE = react_native_twilio_chatTests/Info.plist;
639 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
640 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
641 | OTHER_LDFLAGS = (
642 | "-ObjC",
643 | "-lc++",
644 | "$(inherited)",
645 | );
646 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
647 | PRODUCT_NAME = "$(TARGET_NAME)";
648 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/react_native_twilio_chat.app/react_native_twilio_chat";
649 | };
650 | name = Release;
651 | };
652 | 13B07F941A680F5B00A75B9A /* Debug */ = {
653 | isa = XCBuildConfiguration;
654 | baseConfigurationReference = 058B2C5015276964FC513EAE /* Pods-react_native_twilio_chat.debug.xcconfig */;
655 | buildSettings = {
656 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
657 | CLANG_ENABLE_MODULES = YES;
658 | CURRENT_PROJECT_VERSION = 1;
659 | ENABLE_BITCODE = NO;
660 | INFOPLIST_FILE = react_native_twilio_chat/Info.plist;
661 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
662 | OTHER_LDFLAGS = (
663 | "$(inherited)",
664 | "-ObjC",
665 | "-lc++",
666 | );
667 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
668 | PRODUCT_NAME = react_native_twilio_chat;
669 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
670 | SWIFT_VERSION = 5.0;
671 | VERSIONING_SYSTEM = "apple-generic";
672 | };
673 | name = Debug;
674 | };
675 | 13B07F951A680F5B00A75B9A /* Release */ = {
676 | isa = XCBuildConfiguration;
677 | baseConfigurationReference = 515793399CA1CC6D6CDF1997 /* Pods-react_native_twilio_chat.release.xcconfig */;
678 | buildSettings = {
679 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
680 | CLANG_ENABLE_MODULES = YES;
681 | CURRENT_PROJECT_VERSION = 1;
682 | INFOPLIST_FILE = react_native_twilio_chat/Info.plist;
683 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
684 | OTHER_LDFLAGS = (
685 | "$(inherited)",
686 | "-ObjC",
687 | "-lc++",
688 | );
689 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
690 | PRODUCT_NAME = react_native_twilio_chat;
691 | SWIFT_VERSION = 5.0;
692 | VERSIONING_SYSTEM = "apple-generic";
693 | };
694 | name = Release;
695 | };
696 | 2D02E4971E0B4A5E006451C7 /* Debug */ = {
697 | isa = XCBuildConfiguration;
698 | baseConfigurationReference = A841F9AA914FC2A277D301DA /* Pods-react_native_twilio_chat-tvOS.debug.xcconfig */;
699 | buildSettings = {
700 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
701 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
702 | CLANG_ANALYZER_NONNULL = YES;
703 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
704 | CLANG_WARN_INFINITE_RECURSION = YES;
705 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
706 | DEBUG_INFORMATION_FORMAT = dwarf;
707 | ENABLE_TESTABILITY = YES;
708 | GCC_NO_COMMON_BLOCKS = YES;
709 | INFOPLIST_FILE = "react_native_twilio_chat-tvOS/Info.plist";
710 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
711 | OTHER_LDFLAGS = (
712 | "$(inherited)",
713 | "-ObjC",
714 | "-lc++",
715 | );
716 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.react_native_twilio_chat-tvOS";
717 | PRODUCT_NAME = "$(TARGET_NAME)";
718 | SDKROOT = appletvos;
719 | TARGETED_DEVICE_FAMILY = 3;
720 | TVOS_DEPLOYMENT_TARGET = 10.0;
721 | };
722 | name = Debug;
723 | };
724 | 2D02E4981E0B4A5E006451C7 /* Release */ = {
725 | isa = XCBuildConfiguration;
726 | baseConfigurationReference = 7D4CDBA6C841D07DB1E9DC66 /* Pods-react_native_twilio_chat-tvOS.release.xcconfig */;
727 | buildSettings = {
728 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
729 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
730 | CLANG_ANALYZER_NONNULL = YES;
731 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
732 | CLANG_WARN_INFINITE_RECURSION = YES;
733 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
734 | COPY_PHASE_STRIP = NO;
735 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
736 | GCC_NO_COMMON_BLOCKS = YES;
737 | INFOPLIST_FILE = "react_native_twilio_chat-tvOS/Info.plist";
738 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
739 | OTHER_LDFLAGS = (
740 | "$(inherited)",
741 | "-ObjC",
742 | "-lc++",
743 | );
744 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.react_native_twilio_chat-tvOS";
745 | PRODUCT_NAME = "$(TARGET_NAME)";
746 | SDKROOT = appletvos;
747 | TARGETED_DEVICE_FAMILY = 3;
748 | TVOS_DEPLOYMENT_TARGET = 10.0;
749 | };
750 | name = Release;
751 | };
752 | 2D02E4991E0B4A5E006451C7 /* Debug */ = {
753 | isa = XCBuildConfiguration;
754 | baseConfigurationReference = 0A3466B50B100C16DB4763DC /* Pods-react_native_twilio_chat-tvOSTests.debug.xcconfig */;
755 | buildSettings = {
756 | BUNDLE_LOADER = "$(TEST_HOST)";
757 | CLANG_ANALYZER_NONNULL = YES;
758 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
759 | CLANG_WARN_INFINITE_RECURSION = YES;
760 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
761 | DEBUG_INFORMATION_FORMAT = dwarf;
762 | ENABLE_TESTABILITY = YES;
763 | GCC_NO_COMMON_BLOCKS = YES;
764 | INFOPLIST_FILE = "react_native_twilio_chat-tvOSTests/Info.plist";
765 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
766 | OTHER_LDFLAGS = (
767 | "$(inherited)",
768 | "-ObjC",
769 | "-lc++",
770 | );
771 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.react_native_twilio_chat-tvOSTests";
772 | PRODUCT_NAME = "$(TARGET_NAME)";
773 | SDKROOT = appletvos;
774 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/react_native_twilio_chat-tvOS.app/react_native_twilio_chat-tvOS";
775 | TVOS_DEPLOYMENT_TARGET = 10.1;
776 | };
777 | name = Debug;
778 | };
779 | 2D02E49A1E0B4A5E006451C7 /* Release */ = {
780 | isa = XCBuildConfiguration;
781 | baseConfigurationReference = 25B61C65E38147E2CC328D2A /* Pods-react_native_twilio_chat-tvOSTests.release.xcconfig */;
782 | buildSettings = {
783 | BUNDLE_LOADER = "$(TEST_HOST)";
784 | CLANG_ANALYZER_NONNULL = YES;
785 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
786 | CLANG_WARN_INFINITE_RECURSION = YES;
787 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
788 | COPY_PHASE_STRIP = NO;
789 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
790 | GCC_NO_COMMON_BLOCKS = YES;
791 | INFOPLIST_FILE = "react_native_twilio_chat-tvOSTests/Info.plist";
792 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
793 | OTHER_LDFLAGS = (
794 | "$(inherited)",
795 | "-ObjC",
796 | "-lc++",
797 | );
798 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.react_native_twilio_chat-tvOSTests";
799 | PRODUCT_NAME = "$(TARGET_NAME)";
800 | SDKROOT = appletvos;
801 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/react_native_twilio_chat-tvOS.app/react_native_twilio_chat-tvOS";
802 | TVOS_DEPLOYMENT_TARGET = 10.1;
803 | };
804 | name = Release;
805 | };
806 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
807 | isa = XCBuildConfiguration;
808 | buildSettings = {
809 | ALWAYS_SEARCH_USER_PATHS = NO;
810 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
811 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
812 | CLANG_CXX_LIBRARY = "libc++";
813 | CLANG_ENABLE_MODULES = YES;
814 | CLANG_ENABLE_OBJC_ARC = YES;
815 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
816 | CLANG_WARN_BOOL_CONVERSION = YES;
817 | CLANG_WARN_COMMA = YES;
818 | CLANG_WARN_CONSTANT_CONVERSION = YES;
819 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
820 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
821 | CLANG_WARN_EMPTY_BODY = YES;
822 | CLANG_WARN_ENUM_CONVERSION = YES;
823 | CLANG_WARN_INFINITE_RECURSION = YES;
824 | CLANG_WARN_INT_CONVERSION = YES;
825 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
826 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
827 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
828 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
829 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
830 | CLANG_WARN_STRICT_PROTOTYPES = YES;
831 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
832 | CLANG_WARN_UNREACHABLE_CODE = YES;
833 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
834 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
835 | COPY_PHASE_STRIP = NO;
836 | ENABLE_STRICT_OBJC_MSGSEND = YES;
837 | ENABLE_TESTABILITY = YES;
838 | GCC_C_LANGUAGE_STANDARD = gnu99;
839 | GCC_DYNAMIC_NO_PIC = NO;
840 | GCC_NO_COMMON_BLOCKS = YES;
841 | GCC_OPTIMIZATION_LEVEL = 0;
842 | GCC_PREPROCESSOR_DEFINITIONS = (
843 | "DEBUG=1",
844 | "$(inherited)",
845 | );
846 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
847 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
848 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
849 | GCC_WARN_UNDECLARED_SELECTOR = YES;
850 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
851 | GCC_WARN_UNUSED_FUNCTION = YES;
852 | GCC_WARN_UNUSED_VARIABLE = YES;
853 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
854 | LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
855 | LIBRARY_SEARCH_PATHS = (
856 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
857 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
858 | "\"$(inherited)\"",
859 | );
860 | MTL_ENABLE_DEBUG_INFO = YES;
861 | ONLY_ACTIVE_ARCH = YES;
862 | SDKROOT = iphoneos;
863 | };
864 | name = Debug;
865 | };
866 | 83CBBA211A601CBA00E9B192 /* Release */ = {
867 | isa = XCBuildConfiguration;
868 | buildSettings = {
869 | ALWAYS_SEARCH_USER_PATHS = NO;
870 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
871 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
872 | CLANG_CXX_LIBRARY = "libc++";
873 | CLANG_ENABLE_MODULES = YES;
874 | CLANG_ENABLE_OBJC_ARC = YES;
875 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
876 | CLANG_WARN_BOOL_CONVERSION = YES;
877 | CLANG_WARN_COMMA = YES;
878 | CLANG_WARN_CONSTANT_CONVERSION = YES;
879 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
880 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
881 | CLANG_WARN_EMPTY_BODY = YES;
882 | CLANG_WARN_ENUM_CONVERSION = YES;
883 | CLANG_WARN_INFINITE_RECURSION = YES;
884 | CLANG_WARN_INT_CONVERSION = YES;
885 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
886 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
887 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
888 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
889 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
890 | CLANG_WARN_STRICT_PROTOTYPES = YES;
891 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
892 | CLANG_WARN_UNREACHABLE_CODE = YES;
893 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
894 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
895 | COPY_PHASE_STRIP = YES;
896 | ENABLE_NS_ASSERTIONS = NO;
897 | ENABLE_STRICT_OBJC_MSGSEND = YES;
898 | GCC_C_LANGUAGE_STANDARD = gnu99;
899 | GCC_NO_COMMON_BLOCKS = YES;
900 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
901 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
902 | GCC_WARN_UNDECLARED_SELECTOR = YES;
903 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
904 | GCC_WARN_UNUSED_FUNCTION = YES;
905 | GCC_WARN_UNUSED_VARIABLE = YES;
906 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
907 | LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
908 | LIBRARY_SEARCH_PATHS = (
909 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
910 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
911 | "\"$(inherited)\"",
912 | );
913 | MTL_ENABLE_DEBUG_INFO = NO;
914 | SDKROOT = iphoneos;
915 | VALIDATE_PRODUCT = YES;
916 | };
917 | name = Release;
918 | };
919 | /* End XCBuildConfiguration section */
920 |
921 | /* Begin XCConfigurationList section */
922 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "react_native_twilio_chatTests" */ = {
923 | isa = XCConfigurationList;
924 | buildConfigurations = (
925 | 00E356F61AD99517003FC87E /* Debug */,
926 | 00E356F71AD99517003FC87E /* Release */,
927 | );
928 | defaultConfigurationIsVisible = 0;
929 | defaultConfigurationName = Release;
930 | };
931 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "react_native_twilio_chat" */ = {
932 | isa = XCConfigurationList;
933 | buildConfigurations = (
934 | 13B07F941A680F5B00A75B9A /* Debug */,
935 | 13B07F951A680F5B00A75B9A /* Release */,
936 | );
937 | defaultConfigurationIsVisible = 0;
938 | defaultConfigurationName = Release;
939 | };
940 | 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "react_native_twilio_chat-tvOS" */ = {
941 | isa = XCConfigurationList;
942 | buildConfigurations = (
943 | 2D02E4971E0B4A5E006451C7 /* Debug */,
944 | 2D02E4981E0B4A5E006451C7 /* Release */,
945 | );
946 | defaultConfigurationIsVisible = 0;
947 | defaultConfigurationName = Release;
948 | };
949 | 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "react_native_twilio_chat-tvOSTests" */ = {
950 | isa = XCConfigurationList;
951 | buildConfigurations = (
952 | 2D02E4991E0B4A5E006451C7 /* Debug */,
953 | 2D02E49A1E0B4A5E006451C7 /* Release */,
954 | );
955 | defaultConfigurationIsVisible = 0;
956 | defaultConfigurationName = Release;
957 | };
958 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "react_native_twilio_chat" */ = {
959 | isa = XCConfigurationList;
960 | buildConfigurations = (
961 | 83CBBA201A601CBA00E9B192 /* Debug */,
962 | 83CBBA211A601CBA00E9B192 /* Release */,
963 | );
964 | defaultConfigurationIsVisible = 0;
965 | defaultConfigurationName = Release;
966 | };
967 | /* End XCConfigurationList section */
968 | };
969 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
970 | }
971 |
--------------------------------------------------------------------------------