まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2020/03

LINE Developers から提供されている LIFF(LIne Frontend Framework) は LINE のフロントエンドアプリケーションを開発するためのフレームワークです。このブログでも何度か触れる機会がありました:
http://dotnsf.blog.jp/tag/liff


これまで LIFF は LINE Developers 内の Messaging API チャネルの一部として提供されていましたが、先日のアップデートで Messaging API チャネルからは追加できなくなり今後は LINE Login チャネルの一部として提供されるようになりました:
2020031103

2020031102


さっそく自分がこれまでに作ってきた LIFF アプリも LINE Login チャネルでも動くことを動作確認・・・したのですが、うまく動いてくれないのでした。その記録の意味も兼ねてこのブログエントリを書いています。

(追記 2020/03/14)
解決しました。詳しくは後述。
(追記終わり)


まず LIFF の SDK のバージョンは 2.1 です。これは Messaging API チャネルの頃と同じもの(URL も同じ)です。したがって基本的にアプリケーションソースコードは Messagin API チャネルのものから変更する必要はない(後述の LIFF ID の変更のみ必要)と理解しています。

LINE Login チャネルの中で LIFF アプリを定義する方法や設定内容で動作に違いがでる可能性はあると思っていますが、今回用意した LINE Login チャネル上の LIFF アプリはスコープなど可能な限り緩めの設定にしており、この設定内容が後述のエラーにつながっているとは考えにくいと思っています:
2020031101


作業としては基本的には LIFF SDK v2.1 の作法に従っているだけですが、一応説明します。Messaging API チャネルで作った時と同様に、まずは LIFF アプリ(ウェブアプリ)のエンドポイント URL を指定して LIFF アプリを LINE Login チャネル内に定義します。この時点で LIFF URL が生成され、LIFF ID(LIFF URL の line://app/XXXXXXXXXX の XXXXXXXXXX 部分。下図だと "16" で始まる文字列)が取得できます:
2020031104


次にエンドポイント URL の先で動くウェブアプリケーションを用意します。まず LIFF SDK v2.1 をロードする必要があるため、以下の行をページ内に追加します:
<script src="https://static.line-scdn.net/liff/edge/2.1/sdk.js"></script>

画面ロード時の JavaScript で LIFF を初期化します。この時のパラメーターとして上記で取得した LIFF ID (XXXXXXXXXX 部分)を指定します:
$(function(){
  liff.init( { liffId: 'XXXXXXXXXX' } ).then( function(){
    :
    :
  }).catch( function( err ){
alert( JSON.stringify( err ) ); }); : : });

※ここまでは成功していること(init() 時に catch() 内が実行されていないこと)を確認しています。


初期化が成功していれば LIFF の各種関数が使えるようになります。このアプリでは HTML5 の Canvas を使って指でお絵描きをして、「送信」するとその画像を元のトークルームにスタンプのように送信するという処理を実行しています。もう少し詳しく説明すると、「送信」すると Canvas 内の絵をまず PNG 画像に変換してサーバーにアップロードします。アップロードまでが成功したらその画像を表示するための URL (img_url)を指定して以下のコードを実行しています:
var data = {
  type: "image",
  originalContentUrl: img_url,
  previewImageUrl: img_url
};

liff.sendMessages( [ data] ).then( function(){
  //. トークルームへの送信成功
  alert( '送信されました' );
  liff.closeWindow();
}).catch( function( err ){
  //. トークルームへの送信に失敗
  alert( JSON.stringify( err ) );  //. エラーメッセージを表示
});

指で描いた絵をトークルームに送信する処理が成功すると「送信されました」というメッセージが表示され、LIFF アプリのウィンドウが閉じられます。送信処理に失敗すると LIFF のサーバーから返ってきたエラーオブジェクト(err)を文字列化して表示する、という処理を実行しています。


繰り返しますが、この内容は Messaging API チャネル内に作った LIFF アプリでは成功していました&今でも成功しています。

(Messaging API チャネルでの挙動 LIFF URL をタップしてアプリを起動)
2020031201


(Messaging API チャネルでの挙動 ペンの色や太さを変えながら指でお絵描き)
2020031202


(Messaging API チャネルでの挙動 送信するとトークルームに表示される)
2020031203



しかし同じアプリを LINE Login チャネルに作った LIFF アプリで実行すると、liff.init() は成功するのですが、liff.sendMessages() に失敗します。失敗時に返される err オブジェクトを表示すると以下のようになりました:
2020031203


直接の原因がどこにあるのかはわかりませんが、メッセージでは LIFF SDK の JavaScript 内でエラーが発生していたようで、これ以上の原因調査が難しい状況です(少なくとも今のこの時点では SDK 側に問題があって、誰が実行しても同じ結果になるような気がしています・・・)。


なおここで紹介している LIFF アプリ自体はもともとオープンソースとして公開していました。IBM Cloud を使う前提で作られていますが、無料プランの枠内で使えるものです。現在はこの問題のために動かない(登録済みの Messaging API チャネルの LIFF アプリとすれば動く)状態のものですが、詳細なソースコードはこちらから参照いただくことも可能です:
https://github.com/dotnsf/line_liff_doodle

(↑現在はこの問題を調査するためのデバッグ用コードも多少含まれているので、少し見にくい部分もあると思います。ご了承ください)


(追記 2020/03/13)
全く同じソースコードを Messaging API チャネルで取得した liff_id と、LINE Login チャネルで取得した liff_id だけを変えて、同じサーバーにデプロイして動作確認の比較(ようするに liff.init 実行時のパラメータだけを変えて実験。2つの LIFF アプリのエンドポイント URL は同じ)。

結果: Messaging API チャネルの LIFF アプリではイラスト送信に成功、LINE Login チャネルの LIFF アプリは上述のエラー。

やはり LINE Login チャネルの LIFF アプリでは sendMessages が動作しない可能性が高いと判断。
(追記おわり)



この問題、LINE developers community にも報告済みですが、まだ解決していません。上述しましたが、今から作る LIFF アプリは Messaging API チャネルではなく LINE Login チャネルを使う必要があるため、既に Messaging API チャネルで動いている LIFF アプリはともかく、これから作る LIFF アプリでは動かないように思えます。この LINE お絵描きスタンプは IT 勉強会とかでも人気の開発ネタなので、できれば今でも動くようになって、再び勉強会とかで使えるようになってほしいと思っています。


(追記 2020/03/14)
この問題は LINE developer community で返答があり解決しました。原因としてはアプリの Scopes 設定が足りなかったというものでした。下図の View all ▼と書かれた箇所をクリックすると・・・
2020031401


更に選択肢が出てきました。この中の "chat_message.write" を選択して保存すると、sendMessages を実行する権限が与えられて動くようになるようでした:
2020031402


(愚痴ですが)"View all ▼" って書かれたいたら(既に展開済みで)ここが展開できるように見えない・・・


(追記おわり)

 

Node.js で XML を扱うのは難しいので、いったん JSON に変換してから扱うことが多いと思っています。そんな場合に自分はよく xml2json というライブラリを使っていました。

xml2json はその名前の通り、XML を JSON に変換してくれるパーサーを実装したライブラリです。使い方は例えば以下のような感じで、XML 文字列をそのまま引数にして実行すると、結果が JSON 文字列となって戻してくれます(JSON の文字列ではなく JSON オブジェクトとして扱う場合は更に JSON.parse() を実行します)。挙動も速く、便利に使っていました:
  :
var parser = require( 'xml2json' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonStr = parser.toJson( xmlStr );                   //. XML 文字列を JSON 文字列に変換
var jsonObj = JSON.parse( jsonStr );                     //. JSON 文字列を JSON オブジェクトに変換
  :

ところが上述のような処理を記述した Node.js のソースコードを Windows 環境下で実行しようとした時に問題が発生しました。実行前のライブラリインストール(npm install)の段階でエラーが発生してしまうのでした。詳細なエラーメッセージ等は後述のリンク先を参照していただきたいのですが、node-expat という xml2json の依存ライブラリを node-gyp でビルドする際に何やらエラーが発生していました。

で、この現象を調べた所、どうやら Windows 環境下では xml2json ライブラリ自体がビルドできないという根本的な問題を抱えているようでした:
npm install xml2json error


※厳密には「ビルドできない」わけではないけど、別途 Python や Visual Studio C++ 2012 などの他にインストールする必要があるツールが多く存在しているようです。


↑リンク先でも回避策として「別の XML -> JSON 変換ライブラリを使う」ことが提案されています。というわけで Windows でも使える同機能のライブラリを探したところ、単純な変換であれば fast-xml-parser が使えそうでした。

fast-xml-parser を使う場合は、上述の内容は以下のようなコードになります:
  :
var parser = require( 'fast-xml-parser' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonObj = parser.parse( xmlStr );                    //. XML 文字列を JSON オブジェクトに変換
  :

現実問題として自分個人の開発環境として Windows がベースとなることは今のところ考えにくいのですが、(WSL とかではなく)Windows 環境下で開発しないといけない人との共同作業が発生するようなケースではこういったことも意識しないといけないこともでてくると感じています。


このページのトップヘ