Compare commits

...

13 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
8eda2fcab0 uri: avoid using String.prototype.normalize
It crashes on Android. Well, on the JSC version React Native uses on Android.

While we could use this fallback only on Android, we have decided to use it
on all mobile platforms for consistency.
2019-11-06 15:44:09 +01:00
Saúl Ibarra Corretgé
753b714cd1 Revert "HOTFIX: fix normalizing room names on Android"
This reverts commit d47e6546ac.
2019-11-06 15:39:54 +01:00
Saúl Ibarra Corretgé
3e6a62334d ios: update Podfile.lock 2019-11-05 15:30:18 +01:00
Saúl Ibarra Corretgé
d47e6546ac HOTFIX: fix normalizing room names on Android
"normalize" will raise an exception, probably because the JSC build is not
full-ICU enabled.
2019-11-05 15:24:18 +01:00
Bettenbuk Zoltan
91cab701d4 feat: feature flag for invite functionalities 2019-11-05 15:24:18 +01:00
Bettenbuk Zoltan
4880b85e91 fix BottomSheet shaking 2019-11-05 15:24:18 +01:00
Bettenbuk Zoltan
a9b2236b83 fix: utf-8 room name case sensitivity 2019-11-05 15:24:18 +01:00
Saúl Ibarra Corretgé
0402489472 ios: Xcode 11 support 2019-10-24 15:08:20 +02:00
Saúl Ibarra Corretgé
5d90107875 android: raise SDK and app versions 2019-09-26 13:25:25 +02:00
Saúl Ibarra Corretgé
2d79e08747 deps: react-native-webrtc@latest
Avoid Android crashes.
2019-09-26 13:24:23 +02:00
Saúl Ibarra Corretgé
f702f828e3 android: fix NPE when handling onHostPause
If the Activity is put into the background before the ReactContext is created we
get an NPE here. While the window might be short, it's thechnically possible to
hit this, as our Crashlytics reports show.
2019-09-26 12:31:50 +02:00
Saúl Ibarra Corretgé
26ffde072e android: raise SDK version 2019-09-20 10:26:41 +02:00
Saúl Ibarra Corretgé
c8b20e037e android: make reportConnectedOutgoingCall return a Promise
The call-integration middleware relies on it returning it, as iOS does.
2019-09-20 10:26:28 +02:00
22 changed files with 146 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
osx_image: xcode10.2
osx_image: xcode11.1
language: objective-c
script:
- "./ios/travis-ci/build-ipa.sh"

View File

@@ -20,5 +20,5 @@
android.useAndroidX=true
android.enableJetifier=true
appVersion=19.3.0
sdkVersion=2.3.0
appVersion=19.3.1
sdkVersion=2.3.2

View File

@@ -122,7 +122,7 @@ public class JitsiMeetActivityDelegate {
// https://github.com/facebook/react-native/blob/df4e67fe75d781d1eb264128cadf079989542755/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java#L512
// Why this happens is a mystery wrapped in an enigma.
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (activity == reactContext.getCurrentActivity()) {
if (reactContext != null && activity == reactContext.getCurrentActivity()) {
reactInstanceManager.onHostPause(activity);
}
}

View File

@@ -144,9 +144,10 @@ class RNConnectionService
* @param callUUID - the call's UUID.
*/
@ReactMethod
public void reportConnectedOutgoingCall(String callUUID) {
public void reportConnectedOutgoingCall(String callUUID, Promise promise) {
JitsiMeetLogger.d(TAG + " reportConnectedOutgoingCall " + callUUID);
ConnectionService.setConnectionActive(callUUID);
promise.resolve(null);
}
@Override

View File

@@ -71,6 +71,7 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'YES'
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
end
end
end

View File

@@ -230,7 +230,7 @@ DEPENDENCIES:
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
https://github.com/CocoaPods/Specs.git:
- Amplitude-iOS
- boost-for-react-native
- CocoaLumberjack
@@ -371,6 +371,6 @@ SPEC CHECKSUMS:
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411
PODFILE CHECKSUM: 86bb4d2bc94c6c76b971b9a33e5b2ced9bbfb09f
PODFILE CHECKSUM: c7876b71f44e14fdc5e86181eefd78792c148e55
COCOAPODS: 1.7.2
COCOAPODS: 1.8.1

View File

@@ -41,8 +41,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@@ -52,8 +50,8 @@
ReferencedContainer = "container:app.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -75,8 +73,6 @@
ReferencedContainer = "container:app.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@@ -634,15 +634,22 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -662,14 +669,21 @@
ENABLE_BITCODE = YES;
INFOPLIST_FILE = src/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.JitsiMeetSDK.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};

10
package-lock.json generated
View File

@@ -15513,8 +15513,8 @@
"integrity": "sha512-l3Quzbb+qa4in2U5RSt/lT0/pHrIpEChT1NnqrVAAXNrjkXjVOsxduaaEDdDhTzNJQEm/PcAcoyrFmgvGOohxw=="
},
"react-native-webrtc": {
"version": "github:react-native-webrtc/react-native-webrtc#b1275ccf1e0e083d2a5c238e7d21c37657766463",
"from": "github:react-native-webrtc/react-native-webrtc#b1275ccf1e0e083d2a5c238e7d21c37657766463",
"version": "github:react-native-webrtc/react-native-webrtc#1ce96e1c1fcfdfda2ab1907763c485c580e04963",
"from": "github:react-native-webrtc/react-native-webrtc#1ce96e1c1fcfdfda2ab1907763c485c580e04963",
"requires": {
"base64-js": "^1.1.2",
"event-target-shim": "^1.0.5",
@@ -18607,6 +18607,12 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@@ -80,7 +80,7 @@
"react-native-svg-transformer": "0.13.0",
"react-native-swipeout": "2.3.6",
"react-native-watch-connectivity": "0.2.0",
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#b1275ccf1e0e083d2a5c238e7d21c37657766463",
"react-native-webrtc": "github:react-native-webrtc/react-native-webrtc#1ce96e1c1fcfdfda2ab1907763c485c580e04963",
"react-native-webview": "5.8.1",
"react-redux": "7.1.0",
"react-textarea-autosize": "7.1.0",
@@ -125,6 +125,7 @@
"precommit-hook": "3.0.0",
"string-replace-loader": "2.1.1",
"style-loader": "0.19.0",
"unorm": "1.6.0",
"webpack": "4.26.1",
"webpack-bundle-analyzer": "3.4.1",
"webpack-cli": "3.1.2",

View File

@@ -15,6 +15,7 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
import { loadConfig } from '../base/lib-jitsi-meet';
import { createDesiredLocalTracks } from '../base/tracks';
import {
getBackendSafeRoomName,
getLocationContextRoot,
parseURIString,
toURLString
@@ -85,7 +86,7 @@ export function appNavigate(uri: ?string) {
let url = `${baseURL}config.js`;
// XXX In order to support multiple shards, tell the room to the deployment.
room && (url += `?room=${room.toLowerCase()}`);
room && (url += `?room=${getBackendSafeRoomName(room)}`);
let config;

View File

@@ -23,7 +23,10 @@ import {
participantUpdated
} from '../participants';
import { getLocalTracks, trackAdded, trackRemoved } from '../tracks';
import { getJitsiMeetGlobalNS } from '../util';
import {
getBackendSafeRoomName,
getJitsiMeetGlobalNS
} from '../util';
import {
AUTH_STATUS_CHANGED,
@@ -388,8 +391,7 @@ export function createConference() {
const conference
= connection.initJitsiConference(
// XXX Lib-jitsi-meet does not accept uppercase letters.
room.toLowerCase(), {
getBackendSafeRoomName(room), {
...state['features/base/config'],
applicationName: getName(),
getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats,

View File

@@ -1,5 +1,7 @@
/* @flow */
import { getBackendSafeRoomName } from '../util';
declare var config: Object;
/**
@@ -20,10 +22,8 @@ export default function getRoomName(): ?string {
// URL maps to the room (name). It currently assumes a deployment in
// which the last non-directory component of the path (name) is the
// room.
roomName
= path.substring(path.lastIndexOf('/') + 1).toLowerCase()
|| undefined;
roomName = path.substring(path.lastIndexOf('/') + 1) || undefined;
}
return roomName;
return getBackendSafeRoomName(roomName);
}

View File

@@ -9,7 +9,10 @@ import {
getCurrentConference
} from '../conference';
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
import { parseURIString } from '../util';
import {
getBackendSafeRoomName,
parseURIString
} from '../util';
import {
CONNECTION_DISCONNECTED,
@@ -307,10 +310,7 @@ function _constructOptions(state) {
// Append room to the URL's search.
const { room } = state['features/base/conference'];
// XXX The Jitsi Meet deployments require the room argument to be in
// lower case at the time of this writing but, unfortunately, they do
// not ignore case themselves.
room && (bosh += `?room=${room.toLowerCase()}`);
room && (bosh += `?room=${getBackendSafeRoomName(room)}`);
options.bosh = bosh;
}

View File

@@ -6,6 +6,7 @@ declare var APP: Object;
declare var config: Object;
import { configureInitialDevices } from '../devices';
import { getBackendSafeRoomName } from '../util';
export {
connectionEstablished,
@@ -21,8 +22,7 @@ import logger from './logger';
*/
export function connect() {
return (dispatch: Dispatch<any>, getState: Function) => {
// XXX Lib-jitsi-meet does not accept uppercase letters.
const room = getState()['features/base/conference'].room.toLowerCase();
const room = getBackendSafeRoomName(getState()['features/base/conference'].room);
// XXX For web based version we use conference initialization logic
// from the old app (at the moment of writing).

View File

@@ -61,11 +61,7 @@ class BottomSheet extends PureComponent<Props> {
styles.sheetItemContainer,
_styles.sheet
] }>
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false }>
{ this._getWrappedContent() }
</ScrollView>
{ this._getWrappedContent() }
</View>
</View>
</SlidingView>
@@ -73,24 +69,32 @@ class BottomSheet extends PureComponent<Props> {
}
/**
* Wraps the content when needed (iOS 11 and above), or just returns the original children.
* Wraps the content when needed (iOS 11 and above), or just returns the original content.
*
* @returns {React$Element}
*/
_getWrappedContent() {
const content = (
<ScrollView
bounces = { false }
showsVerticalScrollIndicator = { false } >
{ this.props.children }
</ScrollView>
);
if (Platform.OS === 'ios') {
const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS > 10) {
return (
<SafeAreaView>
{ this.props.children }
{ content }
</SafeAreaView>
);
}
}
return this.props.children;
return content;
}
}

View File

@@ -12,6 +12,12 @@ export const CALENDAR_ENABLED = 'calendar.enabled';
*/
export const CHAT_ENABLED = 'chat.enabled';
/**
* Flag indicating if invite functionality should be enabled.
* Default: enabled (true).
*/
export const INVITE_ENABLED = 'invite.enabled';
/**
* Flag indicating if recording should be enabled in iOS.
* Default: disabled (false).

View File

@@ -0,0 +1,14 @@
// @flow
import * as unorm from 'unorm';
/**
* Applies NFKC normalization to the given text.
* NOTE: Here we use the unorm package because the JSC version in React Native for Android crashes.
*
* @param {string} text - The text that needs to be normalized.
* @returns {string} - The normalized text.
*/
export function normalizeNFKC(text: string) {
return unorm.nfkc(text);
}

View File

@@ -0,0 +1,11 @@
// @flow
/**
* Applies NFKC normalization to the given text.
*
* @param {string} text - The text that needs to be normalized.
* @returns {string} - The normalized text.
*/
export function normalizeNFKC(text: string) {
return text.normalize('NFKC');
}

View File

@@ -1,5 +1,7 @@
// @flow
import { normalizeNFKC } from './strings';
/**
* The app linking scheme.
* TODO: This should be read from the manifest files later.
@@ -96,6 +98,47 @@ function _fixURIStringScheme(uri: string) {
return uri;
}
/**
* Converts a room name to a backend-safe format. Properly lowercased and url encoded.
*
* @param {string?} room - The room name to convert.
* @returns {string?}
*/
export function getBackendSafeRoomName(room: ?string): ?string {
if (!room) {
return room;
}
/* eslint-disable no-param-reassign */
try {
// We do not know if we get an already encoded string at this point
// as different platforms do it differently, but we need a decoded one
// for sure. However since decoding a non-encoded string is a noop, we're safe
// doing it here.
room = decodeURIComponent(room);
} catch (e) {
// This can happen though if we get an unencoded string and it contains
// some characters that look like an encoded entity, but it's not.
// But in this case we're fine goin on...
}
// Normalize the character set.
room = normalizeNFKC(room);
// Only decoded and normalized strings can be lowercased properly.
room = room.toLowerCase();
// But we still need to (re)encode it.
room = encodeURIComponent(room);
/* eslint-enable no-param-reassign */
// Unfortunately we still need to lowercase it, because encoding a string will
// add some uppercase characters, but some backend services
// expect it to be full lowercase. However lowercasing an encoded string
// doesn't change the string value.
return room.toLowerCase();
}
/**
* Gets the (Web application) context root defined by a specific location (URI).
*

View File

@@ -2,6 +2,7 @@
import type { Dispatch } from 'redux';
import { getFeatureFlag, INVITE_ENABLED } from '../../../../base/flags';
import { translate } from '../../../../base/i18n';
import { IconAddPeople } from '../../../../base/icons';
import { connect } from '../../../../base/redux';
@@ -50,7 +51,8 @@ class InviteButton extends AbstractButton<Props, *> {
* @returns {Object}
*/
function _mapStateToProps(state: Object, ownProps: Object) {
const addPeopleEnabled = isAddPeopleEnabled(state) || isDialOutEnabled(state);
const addPeopleEnabled = getFeatureFlag(state, INVITE_ENABLED, true)
&& (isAddPeopleEnabled(state) || isDialOutEnabled(state));
const { visible = Boolean(addPeopleEnabled) } = ownProps;
return {

View File

@@ -192,7 +192,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
const onAppNavigateSettled
= () => this._mounted && this.setState({ joining: false });
this.props.dispatch(appNavigate(encodeURI(room)))
this.props.dispatch(appNavigate(room))
.then(onAppNavigateSettled, onAppNavigateSettled);
}
}