- はじめに
この記事は「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しかできません。
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を生成します。最後はワンクリックで参加リンクを生成します。
- meeting IDを検索
- Generate sinature Generate signatureの部分は公式ドキュメントのままを使います。
- 参加リンクを生成 Meetingサーバーを通すためには
現時点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も暗号化されてます。解決方法は、パスコードを無効にするか(無料アカウントではできない)、またはパスコードを固定する方法があります。セキュリティ観点ではパスコード無効はおすすめしないため、パスコードを固定してます。
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("=");
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の位置とサイズを変更します。
最後までお読みいただきありがとうございます。