[IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982)
* ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server
This commit is contained in:
parent
315d19d37a
commit
255ea84599
|
@ -0,0 +1,6 @@
|
|||
export const SERVERS = 'kServers';
|
||||
export const TOKEN = 'kAuthToken';
|
||||
export const USER_ID = 'kUserId';
|
||||
export const SERVER_URL = 'kAuthServerURL';
|
||||
export const SERVER_NAME = 'kServerName';
|
||||
export const SERVER_ICON = 'kServerIconURL';
|
|
@ -4,6 +4,20 @@ import Realm from 'realm';
|
|||
// Realm.clearTestState();
|
||||
// AsyncStorage.clear();
|
||||
|
||||
const userSchema = {
|
||||
name: 'user',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'string',
|
||||
token: { type: 'string', optional: true },
|
||||
username: { type: 'string', optional: true },
|
||||
name: { type: 'string', optional: true },
|
||||
language: { type: 'string', optional: true },
|
||||
status: { type: 'string', optional: true },
|
||||
roles: { type: 'string[]', optional: true }
|
||||
}
|
||||
};
|
||||
|
||||
const serversSchema = {
|
||||
name: 'servers',
|
||||
primaryKey: 'id',
|
||||
|
@ -370,6 +384,7 @@ class DB {
|
|||
serversDB: new Realm({
|
||||
path: 'default.realm',
|
||||
schema: [
|
||||
userSchema,
|
||||
serversSchema
|
||||
],
|
||||
schemaVersion: 8,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { AsyncStorage, InteractionManager } from 'react-native';
|
||||
import semver from 'semver';
|
||||
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import reduxStore from './createStore';
|
||||
import defaultSettings from '../constants/settings';
|
||||
|
@ -36,6 +37,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
|
|||
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
|
||||
|
||||
import { getDeviceToken } from '../notifications/push';
|
||||
import { SERVERS, SERVER_URL } from '../constants/userDefaults';
|
||||
|
||||
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
||||
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
|
||||
|
@ -58,9 +60,9 @@ const RocketChat = {
|
|||
},
|
||||
async getUserToken() {
|
||||
try {
|
||||
return await AsyncStorage.getItem(TOKEN_KEY);
|
||||
return await RNUserDefaults.get(TOKEN_KEY);
|
||||
} catch (error) {
|
||||
console.warn(`AsyncStorage error: ${ error.message }`);
|
||||
console.warn(`RNUserDefaults error: ${ error.message }`);
|
||||
}
|
||||
},
|
||||
async getServerInfo(server) {
|
||||
|
@ -321,10 +323,26 @@ const RocketChat = {
|
|||
}
|
||||
this.sdk = null;
|
||||
|
||||
try {
|
||||
const servers = await RNUserDefaults.objectForKey(SERVERS);
|
||||
await RNUserDefaults.setObjectForKey(SERVERS, servers && servers.filter(srv => srv[SERVER_URL] !== server));
|
||||
} catch (error) {
|
||||
console.log('logout_rn_user_defaults', error);
|
||||
}
|
||||
|
||||
const { serversDB } = database.databases;
|
||||
|
||||
const userId = await RNUserDefaults.get(`${ TOKEN_KEY }-${ server }`);
|
||||
|
||||
serversDB.write(() => {
|
||||
const user = serversDB.objectForPrimaryKey('user', userId);
|
||||
serversDB.delete(user);
|
||||
});
|
||||
|
||||
Promise.all([
|
||||
AsyncStorage.removeItem('currentServer'),
|
||||
AsyncStorage.removeItem(TOKEN_KEY),
|
||||
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`)
|
||||
RNUserDefaults.clear('currentServer'),
|
||||
RNUserDefaults.clear(TOKEN_KEY),
|
||||
RNUserDefaults.clear(`${ TOKEN_KEY }-${ server }`)
|
||||
]).catch(error => console.log(error));
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AsyncStorage } from 'react-native';
|
||||
import { delay } from 'redux-saga';
|
||||
import {
|
||||
takeLatest, take, select, put, all
|
||||
} from 'redux-saga/effects';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
|
@ -43,8 +43,8 @@ const handleOpen = function* handleOpen({ params }) {
|
|||
}
|
||||
|
||||
const [server, user] = yield all([
|
||||
AsyncStorage.getItem('currentServer'),
|
||||
AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ host }`)
|
||||
RNUserDefaults.get('currentServer'),
|
||||
RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ host }`)
|
||||
]);
|
||||
|
||||
// TODO: needs better test
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { AsyncStorage } from 'react-native';
|
||||
import { put, takeLatest, all } from 'redux-saga/effects';
|
||||
import SplashScreen from 'react-native-splash-screen';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import * as actions from '../actions';
|
||||
import { selectServerRequest } from '../actions/server';
|
||||
|
@ -11,14 +11,46 @@ import RocketChat from '../lib/rocketchat';
|
|||
import log from '../utils/log';
|
||||
import Navigation from '../lib/Navigation';
|
||||
import database from '../lib/realm';
|
||||
import {
|
||||
SERVERS, SERVER_ICON, SERVER_NAME, SERVER_URL, TOKEN, USER_ID
|
||||
} from '../constants/userDefaults';
|
||||
|
||||
const restore = function* restore() {
|
||||
try {
|
||||
const { token, server } = yield all({
|
||||
token: AsyncStorage.getItem(RocketChat.TOKEN_KEY),
|
||||
server: AsyncStorage.getItem('currentServer')
|
||||
yield RNUserDefaults.setName('group.ios.chat.rocket');
|
||||
|
||||
let { token, server } = yield all({
|
||||
token: RNUserDefaults.get(RocketChat.TOKEN_KEY),
|
||||
server: RNUserDefaults.get('currentServer')
|
||||
});
|
||||
|
||||
// get native credentials
|
||||
const { serversDB } = database.databases;
|
||||
const servers = yield RNUserDefaults.objectForKey(SERVERS);
|
||||
if (servers) {
|
||||
serversDB.write(() => {
|
||||
servers.forEach(async(serverItem) => {
|
||||
const serverInfo = {
|
||||
id: serverItem[SERVER_URL],
|
||||
name: serverItem[SERVER_NAME],
|
||||
iconURL: serverItem[SERVER_ICON]
|
||||
};
|
||||
try {
|
||||
serversDB.create('servers', serverInfo, true);
|
||||
await RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ serverInfo.id }`, serverItem[USER_ID]);
|
||||
} catch (e) {
|
||||
log('err_create_servers', e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// if not have current
|
||||
if (servers.length !== 0 && (!token || !server)) {
|
||||
server = servers[0][SERVER_URL];
|
||||
token = servers[0][TOKEN];
|
||||
}
|
||||
|
||||
const sortPreferences = yield RocketChat.getSortPreferences();
|
||||
yield put(setAllPreferences(sortPreferences));
|
||||
|
||||
|
@ -27,8 +59,8 @@ const restore = function* restore() {
|
|||
|
||||
if (!token || !server) {
|
||||
yield all([
|
||||
AsyncStorage.removeItem(RocketChat.TOKEN_KEY),
|
||||
AsyncStorage.removeItem('currentServer')
|
||||
RNUserDefaults.clear(RocketChat.TOKEN_KEY),
|
||||
RNUserDefaults.clear('currentServer')
|
||||
]);
|
||||
yield put(actions.appStart('outside'));
|
||||
} else if (server) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AsyncStorage } from 'react-native';
|
||||
import {
|
||||
put, call, takeLatest, select, take, fork, cancel
|
||||
} from 'redux-saga/effects';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart } from '../actions';
|
||||
|
@ -60,7 +60,7 @@ const fetchUserPresence = function* fetchUserPresence() {
|
|||
const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
||||
try {
|
||||
const adding = yield select(state => state.server.adding);
|
||||
yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token);
|
||||
yield RNUserDefaults.set(RocketChat.TOKEN_KEY, user.token);
|
||||
|
||||
const server = yield select(getServer);
|
||||
yield put(roomsRequest());
|
||||
|
@ -72,7 +72,17 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
yield fork(fetchUserPresence);
|
||||
|
||||
I18n.locale = user.language;
|
||||
yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
|
||||
|
||||
const { serversDB } = database.databases;
|
||||
serversDB.write(() => {
|
||||
try {
|
||||
serversDB.create('user', user, true);
|
||||
} catch (e) {
|
||||
log('err_set_user_token', e);
|
||||
}
|
||||
});
|
||||
|
||||
yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ server }`, user.id);
|
||||
yield put(setUser(user));
|
||||
EventEmitter.emit('connected');
|
||||
|
||||
|
@ -105,7 +115,7 @@ const handleLogout = function* handleLogout() {
|
|||
// see if there's other logged in servers and selects first one
|
||||
if (servers.length > 0) {
|
||||
const newServer = servers[0].id;
|
||||
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
|
||||
const token = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
|
||||
if (token) {
|
||||
return yield put(selectServerRequest(newServer));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import {
|
||||
put, take, takeLatest, fork, cancel, race
|
||||
} from 'redux-saga/effects';
|
||||
import { AsyncStorage, Alert } from 'react-native';
|
||||
import { Alert } from 'react-native';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { SERVER } from '../actions/actionsTypes';
|
||||
|
@ -14,6 +15,7 @@ import RocketChat from '../lib/rocketchat';
|
|||
import database from '../lib/realm';
|
||||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import { SERVERS, TOKEN, SERVER_URL } from '../constants/userDefaults';
|
||||
|
||||
const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
|
||||
try {
|
||||
|
@ -38,13 +40,21 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
|
|||
|
||||
const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) {
|
||||
try {
|
||||
yield AsyncStorage.setItem('currentServer', server);
|
||||
const userStringified = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
const { serversDB } = database.databases;
|
||||
|
||||
if (userStringified) {
|
||||
const user = JSON.parse(userStringified);
|
||||
yield RocketChat.connect({ server, user });
|
||||
yield put(setUser(user));
|
||||
yield RNUserDefaults.set('currentServer', server);
|
||||
const userId = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
const user = userId && serversDB.objectForPrimaryKey('user', userId);
|
||||
|
||||
const servers = yield RNUserDefaults.objectForKey(SERVERS);
|
||||
const userCredentials = servers && servers.find(srv => srv[SERVER_URL] === server);
|
||||
const userLogin = userCredentials && {
|
||||
token: userCredentials[TOKEN]
|
||||
};
|
||||
|
||||
if (user || userLogin) {
|
||||
yield RocketChat.connect({ server, user: user || userLogin });
|
||||
yield put(setUser(user || userLogin));
|
||||
yield put(actions.appStart('inside'));
|
||||
} else {
|
||||
yield RocketChat.connect({ server });
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React, { Component } from 'react';
|
||||
import {
|
||||
View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Image, AsyncStorage
|
||||
View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Image
|
||||
} from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import equal from 'deep-equal';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import RNUserDefaults from 'rn-user-defaults';
|
||||
|
||||
import { toggleServerDropdown as toggleServerDropdownAction } from '../../actions/rooms';
|
||||
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
|
||||
|
@ -124,8 +125,8 @@ class ServerDropdown extends Component {
|
|||
|
||||
this.close();
|
||||
if (currentServer !== server) {
|
||||
const token = await AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
if (!token) {
|
||||
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
if (!userId) {
|
||||
appStart();
|
||||
this.newServerTimeout = setTimeout(() => {
|
||||
EventEmitter.emit('NewServer', { server });
|
||||
|
|
|
@ -39,6 +39,7 @@ const keyExtractor = item => item.rid;
|
|||
|
||||
@connect(state => ({
|
||||
userId: state.login.user && state.login.user.id,
|
||||
isAuthenticated: state.login.isAuthenticated,
|
||||
server: state.server.server,
|
||||
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
|
||||
searchText: state.rooms.searchText,
|
||||
|
@ -111,7 +112,8 @@ export default class RoomsListView extends React.Component {
|
|||
openSearchHeader: PropTypes.func,
|
||||
closeSearchHeader: PropTypes.func,
|
||||
appStart: PropTypes.func,
|
||||
roomsRequest: PropTypes.func
|
||||
roomsRequest: PropTypes.func,
|
||||
isAuthenticated: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -187,7 +189,7 @@ export default class RoomsListView extends React.Component {
|
|||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest
|
||||
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest, isAuthenticated
|
||||
} = this.props;
|
||||
|
||||
if (!(
|
||||
|
@ -197,7 +199,7 @@ export default class RoomsListView extends React.Component {
|
|||
&& (prevProps.showUnread === showUnread)
|
||||
)) {
|
||||
this.getSubscriptions();
|
||||
} else if (appState === 'foreground' && appState !== prevProps.appState) {
|
||||
} else if (appState === 'foreground' && appState !== prevProps.appState && isAuthenticated) {
|
||||
roomsRequest();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ export default class Sidebar extends Component {
|
|||
const permissionsFiltered = database.objects('permissions')
|
||||
.filter(permission => permissions.includes(permission._id));
|
||||
return permissionsFiltered.reduce((result, permission) => (
|
||||
result || permission.roles.some(r => roles.includes(r))),
|
||||
result || permission.roles.some(r => roles.indexOf(r) !== -1)),
|
||||
false);
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
|
||||
1E02221122B2F76B00001862 /* libRNUserDefaults.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E02220D22B2F76400001862 /* libRNUserDefaults.a */; };
|
||||
24A2AEF2383D44B586D31C01 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 06BB44DD4855498082A744AD /* libz.tbd */; };
|
||||
38CEA0ED468E49CFABCD82FD /* libRNFirebase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A36F9982B71E4662AA8DEB77 /* libRNFirebase.a */; };
|
||||
50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C235DC7B31A4D1578EDEF219 /* libPods-RocketChatRN.a */; };
|
||||
|
@ -99,6 +100,13 @@
|
|||
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
|
||||
remoteInfo = React;
|
||||
};
|
||||
1E02220C22B2F76400001862 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RNUserDefaults;
|
||||
};
|
||||
3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
|
||||
|
@ -452,6 +460,7 @@
|
|||
1845C223DA364898A8400573 /* FastImage.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = FastImage.xcodeproj; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = "<group>"; };
|
||||
1A34D902CC074FF1BCC7DB48 /* libimageCropPicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libimageCropPicker.a; sourceTree = "<group>"; };
|
||||
1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSafariViewManager.a; sourceTree = "<group>"; };
|
||||
1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNUserDefaults.xcodeproj; path = "../node_modules/rn-user-defaults/ios/RNUserDefaults.xcodeproj"; sourceTree = "<group>"; };
|
||||
20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = "<group>"; };
|
||||
22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
|
||||
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNI18n.xcodeproj; path = "../node_modules/react-native-i18n/ios/RNI18n.xcodeproj"; sourceTree = "<group>"; };
|
||||
|
@ -492,6 +501,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1E02221122B2F76B00001862 /* libRNUserDefaults.a in Frameworks */,
|
||||
7ACD4897222860DE00442C55 /* JavaScriptCore.framework in Frameworks */,
|
||||
7A8DEB5A20ED0BEC00C5DCE4 /* libRNNotifications.a in Frameworks */,
|
||||
B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */,
|
||||
|
@ -626,6 +636,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1E0221D622B2F76300001862 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E02220D22B2F76400001862 /* libRNUserDefaults.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
22CA7F59107E0C79C2506C7C /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -731,6 +749,7 @@
|
|||
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */,
|
||||
7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */,
|
||||
B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */,
|
||||
7A430E1620238C01008F55BC /* RCTCustomInputController.xcodeproj */,
|
||||
|
@ -1016,6 +1035,10 @@
|
|||
ProductGroup = 7A8DEB1C20ED0BDE00C5DCE4 /* Products */;
|
||||
ProjectRef = 7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 1E0221D622B2F76300001862 /* Products */;
|
||||
ProjectRef = 1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = B8E79A8A1F3CCC6C005B464F /* Products */;
|
||||
ProjectRef = 22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */;
|
||||
|
@ -1085,6 +1108,13 @@
|
|||
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
1E02220D22B2F76400001862 /* libRNUserDefaults.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRNUserDefaults.a;
|
||||
remoteRef = 1E02220C22B2F76400001862 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
|
|
|
@ -8,5 +8,9 @@
|
|||
<array>
|
||||
<string>applinks:go.rocket.chat</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.ios.chat.rocket</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
"redux-saga": "^0.16.2",
|
||||
"remove-markdown": "^0.3.0",
|
||||
"rn-fetch-blob": "^0.10.15",
|
||||
"rn-user-defaults": "^1.3.4",
|
||||
"semver": "6.0.0",
|
||||
"snyk": "^1.156.0",
|
||||
"strip-ansi": "5.2.0"
|
||||
|
|
|
@ -12550,6 +12550,11 @@ rn-fetch-blob@^0.10.15:
|
|||
base-64 "0.1.0"
|
||||
glob "7.0.6"
|
||||
|
||||
rn-user-defaults@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.3.4.tgz#1fbdd1bf29d9f853918dca5219e45db54d19fe37"
|
||||
integrity sha512-CnzZbq3Q1VQUr6wKl9Z48eKmOzu+6dMcl2wN0ty+sBnpUyIqFvv3CMzYzb26v1qK8z7q/PcMr75shFHcrJH9WA==
|
||||
|
||||
rsvp@^3.3.3:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
|
||||
|
|
Loading…
Reference in New Issue