mieszko4 / react-native-zoom-us-test

Example repository of using react-native-zoom-us bridge
16 stars 13 forks source link

Error on ZoomUs.joinMeeting: "[Error: Error: 4, internalErrorCode=0]" #66

Closed tommi97 closed 10 months ago

tommi97 commented 1 year ago

In some Android devices I have the same error when i try to join or start a meeting, with both version 6.15.1 and 6.16.5. IOS work fine.

When i try to join a meeting I recive following event before the "error 4": {"event": "meetingClientIncompatible", "status": "MEETING_STATUS_FAILED"}

How can i resolve this issue in Android?

KhaledOuartsi commented 1 year ago

@tommi97 any update ? i have the same issue on android devices

tommi97 commented 1 year ago

@KhaledOuartsi The problem was that the zoom SDK used form the package is too old, so I decide to use this guide: https://stefan-majiros.com/blog/integrating-zoom-sdk-into-react-native/ to implement my custom bridge from React and Zoom SDK to be free to update the zoom SDK.

After following this guide I found some difficulty because the code doesn't work correctly but after some modifications now it works.

When it finally worked, I changed the startMeeting function to accept ZAK authentication instead of JWT because it will be deprecated.

Finally I copied from this package (react-native-zoom-us) some pieces of code to implement some parameters that I used before like: disableShowVideoPreviewWhenJoinMeeting, language and so on...

I hope I was helpful, Good luck! :muscle:

KhaledOuartsi commented 1 year ago

@tommi97 thank you so much for your reply, Me too i decided to implement my custum bridge, and it's working now

tommi97 commented 1 year ago

You follow my guide or you find another one?

KhaledOuartsi commented 1 year ago

I followed the same link yeah, because i just saw your reply

tommi97 commented 1 year ago

Ok, I am happy to be helpful to you!!

Can you link me your JAVA files so can I check the difference with my code?

You create only android bridge or also IOS?

KhaledOuartsi commented 1 year ago

Ios it was working, i had issues only with android, so i created bridge only for android version,

I will past it here tomorrow.

KhaledOuartsi commented 1 year ago

Hello, This is the bridge working with ZoomSDK 5.10.3 `public class ZoomManager extends ReactContextBaseJavaModule implements ZoomSDKInitializeListener, MeetingServiceListener {

private final ReactApplicationContext reactContext;
private Promise initPromise;
private Promise meetingPromise;

ZoomManager(ReactApplicationContext context) {
    super(context);
    this.reactContext = context;
}

@NonNull
@Override
public String getName() {
    // this defines name of how we will import this module in JS
    return "FDZoomSDKAndroid";
}

@ReactMethod
public void initZoom(String publicKey, String privateKey, String domain, Promise promise) {

    try {
        initPromise = promise;
        this.getReactApplicationContext().getCurrentActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {

                ZoomSDK zoomSDK = ZoomSDK.getInstance();
                ZoomSDKInitParams initParams = new ZoomSDKInitParams();
                initParams.appKey = publicKey;
                initParams.appSecret = privateKey;
                //  initParams.domain = domain;
                zoomSDK.initialize(Objects.requireNonNull(reactContext.getCurrentActivity()),ZoomManager.this, initParams);
            }
        });
    } catch (Exception e) {
        Log.e("ERR_UNEXPECTED_EXCEPTIO", e.getMessage());
        promise.reject("ERR_UNEXPECTED_EXCEPTIO", e);
    }

}

@Override
public void onZoomSDKInitializeResult(int errorCode, int internalErrorCode) {
    Log.d(this.getName(), "Init Zoom Result with : errorCode " + errorCode
            + " and internalErrorCode: " + internalErrorCode);

    if(errorCode == ZoomError.ZOOM_ERROR_SUCCESS) {
        Log.d(this.getName(), "Initializing meeting service SUCCESSFUL");
        ZoomSDK zoomSDK = ZoomSDK.getInstance();
        MeetingService meetingService = zoomSDK.getMeetingService();
        if(meetingService != null) {
            Log.d(this.getName(), "Adding listener for meeting service ");
            meetingService.addListener(this);
        }
        //here we should notify JS
        initPromise.resolve("Zoom initialized");
    }

}

@Override
public void onZoomAuthIdentityExpired() {

}

@Override
public void onMeetingStatusChanged(MeetingStatus meetingStatus, int errorCode, int internalErrorCode) {
    Log.d(this.getName(), "Meeting Status Changed  meetingStatus : " + meetingStatus
            + " errorCode: "  + errorCode + " and internalErrorCode: " + internalErrorCode);

    switch(meetingStatus) {
        case MEETING_STATUS_FAILED: {
            Log.d(this.getName(), "onMeetingStatusChanged: MEETING_STATUS_FAILED");
            break;
        }

        case MEETING_STATUS_DISCONNECTING: {
            Log.d(this.getName(), "onMeetingStatusChanged: MEETING_STATUS_DISCONNECTING");

            break;
        }

        case MEETING_STATUS_INMEETING: {
            Log.d(this.getName(), "onMeetingStatusChanged: MEETING_STATUS_INMEETING");

            break;
        }

        case MEETING_STATUS_IN_WAITING_ROOM: {
            Log.d(this.getName(), "onMeetingStatusChanged: MEETING_STATUS_IN_WAITING_ROOM");

            break;
        }
    }
}

@Override
public void onMeetingParameterNotification(MeetingParameter meetingParameter) {

}

@ReactMethod
public void joinMeeting(String displayName, String meetingNumber, Promise promise) {
    Log.d("ou shit", "Join meeting called : displayName " + displayName
            + " and meetingNumber: " + meetingNumber);
    this.getReactApplicationContext().getCurrentActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            ZoomSDK zoomSDK = ZoomSDK.getInstance();

            if(!zoomSDK.isInitialized()) {
                promise.reject("ERR_ZOOM_START", "ZoomSDK has not been initialized successfully");
                Log.d(getName(), "ZoomSDK has not been initialized successfully");
                return;
            }

            MeetingService meetingService = zoomSDK.getMeetingService();
            if(meetingService == null) {
                promise.reject("ERR_ZOOM_START", "Zoom MeetingService has not been initialized successfully");
                Log.d(getName(), "Zoom MeetingService has not been initialized successfully");

                return;
            }

            JoinMeetingOptions opts = new JoinMeetingOptions();

            JoinMeetingParams params = new JoinMeetingParams();

            params.displayName = displayName;
            params.meetingNo = meetingNumber;
            // params.password = "password";
            try {
                int joinMeetingResult = meetingService.joinMeetingWithParams(reactContext, params,opts);
                Log.i(getName(), "joinMeeting, joinMeetingResult=" + joinMeetingResult);
                if (joinMeetingResult != MeetingError.MEETING_ERROR_SUCCESS) {
                    promise.reject("ERR_ZOOM_JOIN", "joinMeeting, errorCode=" + joinMeetingResult);
                    Log.i(getName(),  "joinMeeting, errorCode=" + joinMeetingResult);

                }
                meetingPromise = promise;

            } catch (Exception e) {
                promise.reject("JoinMeetingException", e);
            }
        }
    });

}

// put in into something like ZakUtils class to make it clean ??
private String getZak(String userId, String jwtApiKey, String jwtApiSecret){

    String jwtAccessToken = this.createJWTAccessToken(jwtApiKey, jwtApiSecret);
    String zak = this.getZoomAccessToken(userId, jwtAccessToken);
    return zak;
}

public String getZoomAccessToken(String userId, String jwtAccessToken) {
    // String jwtAccessToken = createJWTAccessToken();

    if(jwtAccessToken == null || jwtAccessToken.isEmpty())
        return null;
    // Create connection
    try {
        URL zoomTokenEndpoint = new URL("https://api.zoom.us/v2/users/" + userId + "/token?type=zak&access_token=" + jwtAccessToken);
        HttpsURLConnection connection = (HttpsURLConnection) zoomTokenEndpoint.openConnection();

        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
            InputStream responseBody = connection.getInputStream();
            InputStreamReader responseBodyReader = new InputStreamReader(responseBody, "UTF-8");
            BufferedReader streamReader = new BufferedReader(responseBodyReader);
            StringBuilder responseStrBuilder = new StringBuilder();

            //get JSON String
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null)
                responseStrBuilder.append(inputStr);

            connection.disconnect();
            JSONObject jsonObject = new JSONObject(responseStrBuilder.toString());
            return jsonObject.getString("token");
        } else {
            Log.d(this.getName(), "error in connection");
            return null;
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e){
        e.printStackTrace();
    }
    return null;
}

public String createJWTAccessToken(final String API_KEY, final String API_SECRET) {

    long EXPIRED_TIME= 3600 * 2;
    long time=System.currentTimeMillis()/1000  + EXPIRED_TIME;

    String header = "{\"alg\": \"HS256\", \"typ\": \"JWT\"}";
    String payload = "{\"iss\": \"" + API_KEY + "\"" + ", \"exp\": " + String.valueOf(time) + "}";
    try {
        String headerBase64Str = Base64.encodeToString(header.getBytes("utf-8"), Base64.NO_WRAP| Base64.NO_PADDING | Base64.URL_SAFE);
        String payloadBase64Str = Base64.encodeToString(payload.getBytes("utf-8"), Base64.NO_WRAP| Base64.NO_PADDING | Base64.URL_SAFE);
        final Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256");
        mac.init(secretKeySpec);

        byte[] digest = mac.doFinal((headerBase64Str + "." + payloadBase64Str).getBytes());

        return headerBase64Str + "." + payloadBase64Str + "." + Base64.encodeToString(digest, Base64.NO_WRAP| Base64.NO_PADDING | Base64.URL_SAFE);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    return null;
}

}`

khuongphp commented 1 year ago

Pls upgrade your react-native version to ^0.71.3 It worked on my case

mieszko4 commented 1 year ago

I created issue to upgrade Android SDK (https://github.com/mieszko4/react-native-zoom-us/issues/280)

mieszko4 commented 1 year ago

@KhaledOuartsi @tommi97 I am not sure why you used older 5.10.3. based on minimum version policy version 5.12.2 is the minimum supported version from August 5 2023.

In any case idea of react-native-zoom-us and react-native-zoom-us-test is to make it easy to integrate Zoom SDK for others. So I think it would be great if you could make a PR if you managed to resolve some issues that others are experiencing with the bridge :)

mieszko4 commented 10 months ago

I created issue to upgrade Android SDK (mieszko4/react-native-zoom-us#280)

Closing because it is now done in react-native-zoom-us@6.20.0