[RN] Consistency in Jitsi Meet SDK for Android

This commit is contained in:
Lyubo Marinov 2017-06-07 15:15:36 -05:00
parent 84463d8cf0
commit 90466183d6
12 changed files with 233 additions and 209 deletions

View File

@ -1,24 +1,38 @@
# Jitsi Meet for Android
# Jitsi Meet SDK for Android
This directory contains the source code for Jitsi Meet for Android (the
application) and the Jitsi Meet SDK for Android.
This directory contains the source code of the Jitsi Meet app and the Jitsi Meet
SDK for Android.
## Jitsi Meet SDK
Jitsi Meet SDK is an Android library which embodies the Jitsi Meet experience,
gift-wrapped so other applications can use it. Example use:
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
experience and makes it reusable by third-party apps.
To get started, extends your `android.app.Activity` from
`org.jitsi.meet.sdk.JitsiMeetActivity`:
```java
package org.jitsi.example;
import org.jitsi.meet.sdk.JitsiMeetActivity;
public class MainActivity extends JitsiMeetActivity {
}
```
Alternatively, you can use the `org.jitsi.meet.sdk.JitsiMeetView` class which
extends `android.view.View`:
```java
package org.jitsi.example;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import org.jitsi.meet.sdk.*;
import org.jitsi.meet.sdk.JitsiMeetView;
public class CustomActivity extends AppCompatActivity {
private JitsiMeetView jitsiMeetView;
public class MainActivity extends AppCompatActivity {
private JitsiMeetView view;
@Override
public void onBackPressed() {
@ -32,10 +46,17 @@ public class CustomActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
jitsiMeetView = new JitsiMeetView(this);
jitsiMeetView.loadURL(null);
view = new JitsiMeetView(this);
view.loadURL(null);
setContentView(jitsiMeetView);
setContentView(view);
}
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
@Override
@ -43,45 +64,26 @@ public class CustomActivity extends AppCompatActivity {
JitsiMeetView.onNewIntent(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
@Override
protected void onPause() {
super.onPause();
JitsiMeetView.onHostPause(this);
}
@Override
protected void onResume() {
super.onResume();
JitsiMeetView.onHostResume(this);
}
}
```
Alternatively, you can use the `JitsiMeetBaseActivity` class, which already has
all activity lifecycle methods hooked up:
### JitsiMeetActivity
```java
package org.jitsi.example;
import org.jitsi.meet.sdk.*;
public class MainActivity extends JitsiMeetBaseActivity {
}
```
### JitsiMeetBaseActivity
This class encapsulates a high level API in the form of an Android activity
which displays a single `JitsiMeetView` views.
This class encapsulates a high level API in the form of an Android `Activity`
which displays a single `JitsiMeetView`.
#### loadURL(url)
@ -91,7 +93,7 @@ See JitsiMeetView.loadURL.
### JitsiMeetView
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
display a Jitsi Meet conference view (or a welcome page).
display a Jitsi Meet conference (or a welcome page).
#### getListener()
@ -99,8 +101,8 @@ Returns the `JitsiMeetView.Listener` instance attached to the view.
#### loadURL(url)
Loads the given URL and joins the conference which is being pointed to. If null,
it will load the welcome page.
Loads the given URL and joins the room. If `null` is specified, the welcome page
is displayed instead.
#### setListener(listener)
@ -110,8 +112,8 @@ interface) on the view.
#### onBackPressed()
Helper method which should be called from the activity's `onBackPressed` method.
If this function returns `true` it means the action was handled and thus no
extra processing is required, otherwise the application should call the parent's
If this function returns `true`, it means the action was handled and thus no
extra processing is required; otherwise the app should call the parent's
`onBackPressed` method.
This is a static method.
@ -136,16 +138,16 @@ This is a static method.
#### onNewIntent(intent)
Helper method for integrating the *deep linking* functionality. If your
application's activity is launched in "singleTask" mode this method should
be called from the activity's `onNewIntent` method.
Helper method for integrating the *deep linking* functionality. If your app's
activity is launched in "singleTask" mode this method should be called from the
activity's `onNewIntent` method.
This is a static method.
#### Listener
JitsiMeetView.Listener provides an interface applications can implement in order
to get notified about the state of the Jitsi Meet conference.
JitsiMeetView.Listener provides an interface apps can implement in order to get
notified about the state of the Jitsi Meet conference.
##### onConferenceFailed
@ -178,4 +180,3 @@ The `data` HashMap contains a "url" key with the conference URL.
Called before a conference is left.
The `data` HashMap contains a "url" key with the conference URL.

View File

@ -1,6 +1,5 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion

View File

@ -16,18 +16,19 @@
package org.jitsi.meet;
import org.jitsi.meet.sdk.JitsiMeetBaseActivity;
import org.jitsi.meet.sdk.JitsiMeetActivity;
/**
* The one and only Activity that Jitsi Meet (the app) needs. The activity is launched in
* "singleTask" mode, so it will be created upon application initialization and there will be
* a single instance of it. Further attempts at launching the application once it was already
* launched will result in <tt>onNewIntent</tt> being called.
* The one and only {@link Activity} that the Jitsi Meet app needs. The
* {@code Activity} is launched in {@code singleTask} mode, so it will be
* created upon application initialization and there will be a single instance
* of it. Further attempts at launching the application once it was already
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
*
* This Activity inherits from JitsiMeetBaseActivity without adding anything to it. It merely exists to
* keep the React Native CLI working, since it always tries to launch an activity called
* "MainActivity" when doing "react-native run-android".
* This {@code Activity} extends {@link JitsiMeetActivity} without adding
* anything to it. It exists to merely keep the React Native CLI working, since
* the latter always tries to launch an {@code Activity} named
* {@code MainActivity} when doing {@code react-native run-android}.
*/
public class MainActivity extends JitsiMeetBaseActivity {
public class MainActivity extends JitsiMeetActivity {
}

View File

@ -1,4 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// Top-level build file where you can add configuration options common to all
// sub-projects/modules.
buildscript {
repositories {
@ -8,7 +9,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
// in the individual module build.gradle files.
}
}
@ -17,7 +18,8 @@ allprojects {
mavenLocal()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
// All of React Native (JS, Obj-C sources, Android binaries) is
// installed from npm.
url "$rootDir/../node_modules/react-native/android"
}
}

View File

@ -47,7 +47,7 @@ gradle.projectsEvaluated {
def buildNameCapitalized = "${buildType.name.capitalize()}"
def bundlePath = "${buildDir}/intermediates/bundles/${buildType.name}"
// Bundle fonts in react-native-vector-icons
// Bundle fonts in react-native-vector-icons.
//
def currentFontTask = tasks.create(name: "${buildType.name}CopyFonts", type: Copy) {
@ -63,35 +63,43 @@ gradle.projectsEvaluated {
runBefore("processUniversal${buildNameCapitalized}Resources", currentFontTask)
runBefore("process${buildNameCapitalized}Resources", currentFontTask)
// Bundle JavaScript and React resources
// Bundle JavaScript and React resources.
// (adapted from react-native/react.gradle)
//
// React js bundle directories
// React JS bundle directories
def jsBundleDir = file("${bundlePath}/assets")
def resourcesDir = file("${bundlePath}/res/merged")
def jsBundleFile = file("${jsBundleDir}/index.android.bundle")
// Bundle task name for variant
// Bundle task name for variant.
def bundleJsAndAssetsTaskName = "bundle${buildNameCapitalized}JsAndAssets"
def currentBundleTask = tasks.create(
name: bundleJsAndAssetsTaskName,
type: Exec) {
// Set up inputs and outputs so gradle can cache the result
// Set up inputs and outputs so gradle can cache the result.
def reactRoot = file("${projectDir}/../../")
inputs.files fileTree(dir: reactRoot, excludes: ["android/**", "ios/**"])
outputs.dir jsBundleDir
outputs.dir resourcesDir
// Set up the call to the react-native cli
// Set up the call to the react-native cli.
workingDir reactRoot
// Create JS bundle
def devEnabled = !buildNameCapitalized.toLowerCase().contains("release")
commandLine("node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}",
"--reset-cache", "--entry-file", "index.android.js", "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir)
commandLine(
"node",
"node_modules/react-native/local-cli/cli.js",
"bundle",
"--assets-dest", resourcesDir,
"--bundle-output", jsBundleFile,
"--dev", "${devEnabled}",
"--entry-file", "index.android.js",
"--platform", "android",
"--reset-cache")
// TODO: disable task in Debug mode?
}

View File

@ -26,53 +26,57 @@ import android.os.Bundle;
import java.net.URL;
/**
* Base Activity for applications integrating Jitsi Meet at a higher level. It contains all the
* required wiring between the <tt>JKConferenceView</tt> and the Activity lifecycle methods already
* implemented.
* Base Activity for applications integrating Jitsi Meet at a higher level. It
* contains all the required wiring between the <tt>JKConferenceView</tt> and
* the Activity lifecycle methods already implemented.
*
* In this activity we use a single <tt>JKConferenceView</tt> instance. This instance gives us
* access to a view which displays the welcome page and the conference itself. All lifetime methods
* associated with this Activity are hooked to the React Native subsystem via proxy calls through
* the <tt>JKConferenceView</tt> static methods.
* In this activity we use a single <tt>JKConferenceView</tt> instance. This
* instance gives us access to a view which displays the welcome page and the
* conference itself. All lifetime methods associated with this Activity are
* hooked to the React Native subsystem via proxy calls through the
* <tt>JKConferenceView</tt> static methods.
*/
public class JitsiMeetBaseActivity extends AppCompatActivity {
public class JitsiMeetActivity extends AppCompatActivity {
/**
* Instance of the {@JitsiMeetView} which this activity will display.
*/
private JitsiMeetView jitsiMeetView;
/**
* Code for identifying the permission to draw on top of other apps. The number is chosen
* arbitrarily and used to correlate the intent with its result.
* Code for identifying the permission to draw on top of other apps. The
* number is chosen arbitrarily and used to correlate the intent with its
* result.
*/
public static final int OVERLAY_PERMISSION_REQ_CODE = 4242;
/**
* Loads the given URL and displays the conference. If the specified URL is null, the welcome
* page is displayed instead.
* Instance of the {@JitsiMeetView} which this activity will display.
*/
private JitsiMeetView view;
/**
* Loads the given URL and displays the conference. If the specified URL is
* null, the welcome page is displayed instead.
*
* @param url - The conference URL.
*/
public void loadURL(@Nullable URL url) {
jitsiMeetView.loadURL(url);
view.loadURL(url);
}
/**
* {@inheritDoc}
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
protected void onActivityResult(
int requestCode,
int resultCode,
Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// Permission not granted...
// Permission not granted.
return;
}
}
setContentView(jitsiMeetView);
setContentView(view);
}
}
@ -94,24 +98,34 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
jitsiMeetView = new JitsiMeetView(this);
jitsiMeetView.loadURL(null);
/**
* In debug mode React needs permission to write over other apps in order to display the
* warning and error overlays.
*/
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
!Settings.canDrawOverlays(this)) {
view = new JitsiMeetView(this);
view.loadURL(null);
// In debug mode React needs permission to write over other apps in
// order to display the warning and error overlays.
if (BuildConfig.DEBUG
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& !Settings.canDrawOverlays(this)) {
Intent intent
= new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
= new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
return;
}
setContentView(jitsiMeetView);
setContentView(view);
}
/**
* {@inheritDoc}
*/
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
/**
@ -122,21 +136,13 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
JitsiMeetView.onNewIntent(intent);
}
/**
* {@inheritDoc}
*/
@Override
protected void onDestroy() {
super.onDestroy();
JitsiMeetView.onHostDestroy(this);
}
/**
* {@inheritDoc}
*/
@Override
protected void onPause() {
super.onPause();
JitsiMeetView.onHostPause(this);
}
@ -146,7 +152,7 @@ public class JitsiMeetBaseActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
JitsiMeetView.onHostResume(this);
}
}

View File

@ -32,56 +32,58 @@ import com.facebook.react.common.LifecycleState;
import java.net.URL;
import java.util.HashMap;
public class JitsiMeetView extends FrameLayout {
/**
* Background color used by this view and the React Native root view.
* Background color used by {@code JitsiMeetView} and the React Native root
* view.
*/
private static final int BACKGROUND_COLOR = 0xFF111111;
/**
* {@JitsiMeetView.Listener} instance for reporting events occurring in Jitsi Meet.
* Reference to the single instance of this class we currently allow. It's
* currently used for fetching the instance from the listener's callbacks.
*
* TODO: lift this limitation.
*/
private static JitsiMeetView instance;
/**
* React Native bridge. The instance manager allows embedding applications
* to create multiple root views off the same JavaScript bundle.
*/
private static ReactInstanceManager reactInstanceManager;
/**
* {@JitsiMeetView.Listener} instance for reporting events occurring in
* Jitsi Meet.
*/
private JitsiMeetView.Listener listener;
/**
* Reference to the single instance of this class we currently allow. It's currently used for
* fetching the instance from the listener's callbacks.
*
* TODO: lift this limitation.
*/
private static JitsiMeetView mInstance;
/**
* React Native bridge. The instance manager allows embedding applications to create multiple
* root views off the same JavaScript bundle.
*/
private static ReactInstanceManager mReactInstanceManager;
/**
* React Native root view.
*/
private ReactRootView mReactRootView;
private ReactRootView reactRootView;
public JitsiMeetView(@NonNull Context context) {
super(context);
if (mInstance != null) {
throw new RuntimeException("Only a single instance is currently allowed");
if (instance != null) {
throw new RuntimeException(
"Only a single instance is currently allowed");
}
/*
* TODO: Only allow a single instance for now. All React Native modules are
* kinda singletons so global state would be broken since we have a single
* bridge. Once we have that sorted out multiple instances of JitsiMeetView
* will be allowed.
* TODO: Only allow a single instance for now. All React Native modules
* are kinda singletons so global state would be broken since we have a
* single bridge. Once we have that sorted out multiple instances of
* JitsiMeetView will be allowed.
*/
mInstance = this;
instance = this;
setBackgroundColor(BACKGROUND_COLOR);
if (mReactInstanceManager == null) {
initReactInstanceManager(((Activity)context).getApplication());
if (reactInstanceManager == null) {
initReactInstanceManager(((Activity) context).getApplication());
}
}
@ -91,7 +93,7 @@ public class JitsiMeetView extends FrameLayout {
* @returns The {@JitsiMeetView} instance.
*/
public static JitsiMeetView getInstance() {
return mInstance;
return instance;
}
/**
@ -104,14 +106,15 @@ public class JitsiMeetView extends FrameLayout {
}
/**
* Internal method to initialize the React Native instance manager. We create a single instance
* in order to load the JavaScript bundle a single time. All <tt>ReactRootView</tt> instances
* will be tied to the one and only <tt>ReactInstanceManager</tt>.
* Internal method to initialize the React Native instance manager. We
* create a single instance in order to load the JavaScript bundle a single
* time. All <tt>ReactRootView</tt> instances will be tied to the one and
* only <tt>ReactInstanceManager</tt>.
*
* @param application - <tt>Application</tt> instance which is running.
*/
private static void initReactInstanceManager(Application application) {
mReactInstanceManager = ReactInstanceManager.builder()
reactInstanceManager = ReactInstanceManager.builder()
.setApplication(application)
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
@ -130,8 +133,8 @@ public class JitsiMeetView extends FrameLayout {
}
/**
* Loads the given URL and displays the conference. If the specified URL is null, the welcome
* page is displayed instead.
* Loads the given URL and displays the conference. If the specified URL is
* null, the welcome page is displayed instead.
*
* @param url - The conference URL.
*/
@ -142,17 +145,18 @@ public class JitsiMeetView extends FrameLayout {
props.putString("url", url.toString());
}
// TODO: ReactRootView#setAppProperties is only available on React Native 0.45, so destroy
// the current root view and create a new one.
if (mReactRootView != null) {
removeView(mReactRootView);
mReactRootView = null;
// TODO: ReactRootView#setAppProperties is only available on React
// Native 0.45, so destroy the current root view and create a new one.
if (reactRootView != null) {
removeView(reactRootView);
reactRootView = null;
}
mReactRootView = new ReactRootView(getContext());
mReactRootView.startReactApplication(mReactInstanceManager, "App", props);
mReactRootView.setBackgroundColor(BACKGROUND_COLOR);
addView(mReactRootView);
reactRootView = new ReactRootView(getContext());
reactRootView
.startReactApplication(reactInstanceManager, "App", props);
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
addView(reactRootView);
}
/**
@ -165,15 +169,17 @@ public class JitsiMeetView extends FrameLayout {
}
/**
* Activity lifecycle method which should be called from <tt>Activity.onBackPressed</tt> so
* we can do the required internal processing.
* Activity lifecycle method which should be called from
* <tt>Activity.onBackPressed</tt> so we can do the required internal
* processing.
*
* @return - true if the back-press was processed, false otherwise. In case false is returned
* the application should call the parent's implementation.
* @return - true if the back-press was processed, false otherwise. In case
* false is returned the application should call the parent's
* implementation.
*/
public static boolean onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
if (reactInstanceManager != null) {
reactInstanceManager.onBackPressed();
return true;
} else {
return false;
@ -181,52 +187,54 @@ public class JitsiMeetView extends FrameLayout {
}
/**
* Activity lifecycle method which should be called from <tt>Activity.onDestroy</tt> so
* we can do the required internal processing.
* Activity lifecycle method which should be called from
* <tt>Activity.onDestroy</tt> so we can do the required internal
* processing.
*
* @param activity - <tt>Activity</tt> being destroyed.
*/
public static void onHostDestroy(Activity activity) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(activity);
if (reactInstanceManager != null) {
reactInstanceManager.onHostDestroy(activity);
}
}
/**
* Activity lifecycle method which should be called from <tt>Activity.onPause</tt> so
* we can do the required internal processing.
* Activity lifecycle method which should be called from
* <tt>Activity.onPause</tt> so we can do the required internal processing.
*
* @param activity - <tt>Activity</tt> being paused.
*/
public static void onHostPause(Activity activity) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(activity);
if (reactInstanceManager != null) {
reactInstanceManager.onHostPause(activity);
}
}
/**
* Activity lifecycle method which should be called from <tt>Activity.onResume</tt> so
* we can do the required internal processing.
* Activity lifecycle method which should be called from
* <tt>Activity.onResume</tt> so we can do the required internal processing.
*
* @param activity - <tt>Activity</tt> being resumed.
*/
public static void onHostResume(Activity activity) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(activity, null);
if (reactInstanceManager != null) {
reactInstanceManager.onHostResume(activity, null);
}
}
/**
* Activity lifecycle method which should be called from <tt>Activity.onNewIntent</tt> so
* we can do the required internal processing. Note that this is only needed if the activity's
* "launchMode" was set to "singleTask". This is required for deep linking to work once the
* application is already running.
* Activity lifecycle method which should be called from
* <tt>Activity.onNewIntent</tt> so we can do the required internal
* processing. Note that this is only needed if the activity's "launchMode"
* was set to "singleTask". This is required for deep linking to work once
* the application is already running.
*
* @param intent - <tt>Intent</tt> instance which was received.
*/
public static void onNewIntent(Intent intent) {
if (mReactInstanceManager != null) {
mReactInstanceManager.onNewIntent(intent);
if (reactInstanceManager != null) {
reactInstanceManager.onNewIntent(intent);
}
}
@ -235,33 +243,38 @@ public class JitsiMeetView extends FrameLayout {
*/
public interface Listener {
/**
* Called when joining a conference fails or an ongoing conference is interrupted due to a
* failure.
* @param data - HashMap with an "error" key describing the problem, and a "url" key with
* the conference URL.
* Called when joining a conference fails or an ongoing conference is
* interrupted due to a failure.
*
* @param data - HashMap with an "error" key describing the problem, and
* a "url" key with the conference URL.
*/
void onConferenceFailed(HashMap<String, Object> data);
/**
* Called when a conference was joined.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceJoined(HashMap<String, Object> data);
/**
* Called when the conference was left, typically after hanging up.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceLeft(HashMap<String, Object> data);
/**
* Called before the conference is joined.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceWillJoin(HashMap<String, Object> data);
/**
* Called before the conference is left.
*
* @param data - HashMap with a "url" key with the conference URL.
*/
void onConferenceWillLeave(HashMap<String, Object> data);

View File

@ -25,7 +25,6 @@ import org.jitsi.meet.sdk.JitsiMeetView;
import java.util.HashMap;
/**
* Module implementing a simple API to enable a proximity sensor-controlled
* wake lock. When the lock is held, if the proximity sensor detects a nearby
@ -61,20 +60,22 @@ public class ExternalAPIModule extends ReactContextBaseJavaModule {
/**
* Dispatches an event that occurred on JavaScript to the view's listener.
*
* @param name - Event name.
* @param data - Ancillary data for the event.
*/
@ReactMethod
public void sendEvent(final String name, ReadableMap data) {
JitsiMeetView view = JitsiMeetView.getInstance();
JitsiMeetView.Listener listener = view != null ? view.getListener() : null;
JitsiMeetView.Listener listener
= view != null ? view.getListener() : null;
if (listener == null) {
return;
}
// TODO: Sigh, converting a ReadableMap to a HashMap is not supported until React Native
// 0.46.
// TODO: Sigh, converting a ReadableMap to a HashMap is not supported
// until React Native 0.46.
final HashMap<String, Object> dataMap = new HashMap<>();
try {

View File

@ -45,7 +45,7 @@ public class ExternalAPIPackage implements ReactPackage {
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ExternalAPIModule(reactContext));
@ -58,7 +58,7 @@ public class ExternalAPIPackage implements ReactPackage {
*/
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -108,4 +108,3 @@ The `data` dictionary contains a "url" key with the conference URL.
Called before a conference is left.
The `data` dictionary contains a "url" key with the conference URL.

View File

@ -18,7 +18,6 @@
#import "JitsiMeetView.h"
@interface ExternalAPI : NSObject<RCTBridgeModule>
@end
@ -40,25 +39,20 @@ RCT_EXPORT_METHOD(sendEvent:(NSString*)name data:(NSDictionary *) data) {
return;
}
if ([name isEqualToString:@"CONFERENCE_FAILED"] &&
[delegate respondsToSelector:@selector(conferenceFailed:)]) {
if ([name isEqualToString:@"CONFERENCE_FAILED"]
&& [delegate respondsToSelector:@selector(conferenceFailed:)]) {
[delegate conferenceFailed:data];
} else if ([name isEqualToString:@"CONFERENCE_JOINED"] &&
[delegate respondsToSelector:@selector(conferenceJoined:)]) {
} else if ([name isEqualToString:@"CONFERENCE_JOINED"]
&& [delegate respondsToSelector:@selector(conferenceJoined:)]) {
[delegate conferenceJoined:data];
} else if ([name isEqualToString:@"CONFERENCE_LEFT"] &&
[delegate respondsToSelector:@selector(conferenceLeft:)]) {
} else if ([name isEqualToString:@"CONFERENCE_LEFT"]
&& [delegate respondsToSelector:@selector(conferenceLeft:)]) {
[delegate conferenceLeft:data];
} else if ([name isEqualToString:@"CONFERENCE_WILL_JOIN"] &&
[delegate respondsToSelector:@selector(conferenceWillJoin:)]) {
} else if ([name isEqualToString:@"CONFERENCE_WILL_JOIN"]
&& [delegate respondsToSelector:@selector(conferenceWillJoin:)]) {
[delegate conferenceWillJoin:data];
} else if ([name isEqualToString:@"CONFERENCE_WILL_LEAVE"] &&
[delegate respondsToSelector:@selector(conferenceWillLeave:)]) {
} else if ([name isEqualToString:@"CONFERENCE_WILL_LEAVE"]
&& [delegate respondsToSelector:@selector(conferenceWillLeave:)]) {
[delegate conferenceWillLeave:data];
}
}

View File

@ -32,7 +32,7 @@
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation;
+ (instancetype) getInstance;
+ (instancetype)getInstance;
- (void)loadURL:(nullable NSURL *)url;