LoginSignup
2
0

More than 1 year has passed since last update.

Zoom Meeting SDK Web Component viewを試してみた

Last updated at Posted at 2022-07-18
  1. はじめに

この記事は「Qiita Engineer Festa 2022」に参加するための記事です。

株式会社フレクトの先端技術室に務めるエンジニアです。今回はZoom meeting sdkのComponent viewを実装してみました。

2.Component viewとClient viewの違い

Client viewの方がnativeのzoomに似ていて、Web版zoomという感じになります。それに対して、Component viewはZoomウェジット化されたUIになります。

両者の内部が違って、サポートされている機能も異なります。

例えば、Client viewの方は初期化後でも言語が変更できるが、Component viewの方は変更ができません。逆にComponent viewはUIの位置と表示の有無の変更ができますが、Client viewの方が基本変更できません。

両者の使い分け方法としては、できるだけZoomの見た目に再現したいならClient view、いろいろなUIの変更を行いたいならComponent viewになると思います。下のような構築はComponent viewしかできません。

Component view

3.システム環境

Amazon EC2のARMアーキテクチャで実装してみた。Instance環境はt4g.medium。

最初はt4g.smallで足りると思ってましたが、githubのnpm buildがメモリー不足で実施できませんでした。従って、t4g.mediumが必要です。

実装方法は簡単で、github cloneして,npm install && npm runで完了です。後は API_KEY and API_SECRET tools/nav.jsに追加するだけです。

ユーザー視点からどうすればもっと使いやすのか、2点を改良してみました。

4.Component viewの改良1 ワンクリックでMeetingに参加する

Component view一つの不便なところは、ワンクリック参加という機能が存在してないです。現在の使用はLoginページでmeeting ID、パスコードやuser nameを入力して入室する形になります。

しかし、皆様は普段zoomを使っている時パスコード以外は入力しないですよね。こういう観点で見ると、手間がかかります。

Pythonでワンクリック参加機能を実装してみました。

流れとしては、まずZoom APIでユーザーのmeeting IDを検索します。次はsignaureを生成します。最後はワンクリックで参加リンクを生成します。

  1. meeting IDを検索
  2. 現時点instant meetingをAPIでは検知できません。

    Access Tokenの生成について、JWT appは非推奨になったため、Server-to-server-oauth-appがおすすめです。

    https://marketplace.zoom.us/docs/guides/build/server-to-server-oauth-app

    Server-to-server-oauth-appがない場合は、まず作成する必要があります。

    以下のコードでaccess tokenが生成できます。client_id、client_secretとaccount_idをそれぞれを入れ替えてください。

    encodedData = base64.b64encode(bytes(f"{client_id}:{client_secret}", "ISO-8859-1")).decode("ascii")
    headers= f"Authorization: Basic {encodedData}"
    join_url = ''
    
    headers = {
        'Authorization': 'Basic {}'.format(encodedData),
    }
    params = {
        'grant_type': 'account_credentials',
    }
    
    response = requests.post('https://zoom.us/oauth/token?grant_type=account_credentials&account_id={}'.format("account_id"), params=params, headers=headers)
    

    Access tokenが作成できたため、いろんなAPI callが実現できます。今回は最新のmeeting idを取得します。

    # get meetings
    headers = {
        'authorization': "Bearer {}".format(json.loads(response.text)['access_token']),
        'content-type': "application/json"
        }
    response = requests.get("https://api.zoom.us/v2/users/cT62Uo3aSh-sroNrY_tUrg/meetings", headers=headers)
    meetings = json.loads(response.text)
    try:
        number = len(meetings["meetings"])
        id = (meetings["meetings"][number-1]['id'])
    except Exception as e:
        print("Some error has occured")
    

    Zoom APIではパスコードを取得できません。普通の参加URLも暗号化されてます。解決方法は、パスコードを無効にするか(無料アカウントではできない)、またはパスコードを固定する方法があります。セキュリティ観点ではパスコード無効はおすすめしないため、パスコードを固定してます。

  3. Generate sinature
  4. Generate signatureの部分は公式ドキュメントのままを使います。

    https://marketplace.zoom.us/docs/sdk/native-sdks/web/signature/

    def generateSignature(data):
        ts = int(round(time.time() * 1000)) - 30000;
        msg = data['apiKey'] + str(data['meetingNumber']) + str(ts) + str(data['role']);
        message = base64.b64encode(bytes(msg, 'utf-8'));
        secret = bytes(data['apiSecret'], 'utf-8')
        hash = hmac.new(secret, message, hashlib.sha256);
        hash =  base64.b64encode(hash.digest());
        hash = hash.decode("utf-8");
        tmpString = "%s.%s.%s.%s.%s" % (data['apiKey'], str(data['meetingNumber']), str(ts), str(data['role']), hash);
        signature = base64.b64encode(bytes(tmpString, "utf-8"));
        signature = signature.decode("utf-8");
        return signature.rstrip("=");
    
  5. 参加リンクを生成
  6. Meetingサーバーを通すためにはname={}&mn={}&email=&pwd={}&role=0&lang=en-Us&signature={}&china=0&apiKey={} を入力する必要があります。それぞれのパラメータを説明します。

    nameはユーザー名です。このユーザー名は平文ではなく、base64に暗号化した必要があります。

    mnは先ほど取得したmeeting numberです。

    emailは入力必要がありませんので、そのまま空にします。

    pwはパスコードです。固定にしているなら、環境変数で取得できます。

    roleはホストか参加者のことです。0は参加者、1はホスト。

    langは言語です。

    signatureは2番で生成したsignatureです。

    chinaは中国大陸であるかどうかです。そのままにします。

    apiKeyはSDKのAPIのapiKeyです。Oauth appのapikeyではなくため、間違いしないように。

    以下のコードはワンクリックリンクを生成できます。

    data = {'apiKey': api_key,
                    'apiSecret': "",
                    'meetingNumber': ,
                    'role': 0}
    signature=(generateSignature(data))
    meeting_number = number
    password = ''
    sdk_Key = ''
    name = base64.urlsafe_b64encode(b"{}".format("user_name"))
    meeting_url = 'https://input_your_site.com/cdn.html?name={}&mn={}&email=&pwd={}&role=0&lang=en-Us&signature={}&china=0&apiKey={}'.\
    format(codecs.decode(name),meeting_number, password, signature, api_key)
    

    HTTPSを実施しないといろんな機能が制限されてます。カメラが使えない、またチャットも使えません。少なくてもself-signed certificateを使いましょう。

    先ほど生成したリンクをサーバーでreturn '<a href={}>Join the zoom meeting</a>'.format(meeting_url)で返せばリンクを生成できます。それをクリックすれば何も入力せずに参加できます。signatureは有効期限があるため、使う直前までに呼びましょう。

5.Component viewの改良2 チャットUIを最初に表示する

Component viewもう一つの不便なところは、チャットボックスが存在してますが、ユーザーがクリックしないと表示しません。現時点SDKでは調整できません。しかも2回クリックが必要で、チャットが必要と想定されている場合は、ユーザーとして面倒です。

よく使われている$(window).bind()は、ウェジットがロード完了したか確認できません。従って使うとエラーになります。

解決方法としては、Jqueryを実施し、自動的にelementをクリックすれば、最初に出るようになります。

public/cdn.htmlというファイルを以下のように追加すればできます。既存コードは省略されてます。

<!DOCTYPE html>
<html>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

</head>
<body>
    <script>    
    // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists
      function waitForElm(selector) {
          return new Promise(resolve => {
              if (document.querySelector(selector)) {
                  return resolve(document.querySelector(selector));
              }

              const observer = new MutationObserver(mutations => {
                  if (document.querySelector(selector)) {
                      resolve(document.querySelector(selector));
                      observer.disconnect();
                  }
              });

              observer.observe(document.body, {
                  childList: true,
                  subtree: true
              });
          });
      }
      waitForElm('.zmwebsdk-MuiSvgIcon-root').then((elm) => {
          $(".zmwebsdk-MuiSvgIcon-root")[8].closest("button").click();
          $(".zmwebsdk-MuiListItem-button")[0].click()
      });
    </script>
</body>
</html>

参照元
https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists

簡単に説明すると、Jqueryを使用してelementを2回をクリックだけです。もちろんClient view自体はロードする時間がかかりますので、zmwebsdk-MuiSvgIcon-rootで表示できるまで待つ必要があります。

6.次のStep

今回Web Component view機能を試して、改善してみました。まだ改善できていない、次実現したいところをリストします:
1.Instant meetingが作成した後、自動的にサーバーに送信する仕組み、またInvite LinkとInvitation textどちらもはmeeting情報をコピーした後、自動的にmeeting情報を引き出します。
2.ユーザーのIPを検知して、自動的に言語を変更します。
3.現在ユーザーが自由にウェジットを動かすことはできますが、サーバー側は一応初期化した後は変更ができません。初期化後でもJavascriptでUIの位置とサイズを変更します。

最後までお読みいただきありがとうございます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0