ブラウザのjavascriptのみを使ってipa展開からplist解析まで
移転しました →
ここ数日取り組んでだことについてまとめます。iPhoneアプリのバイナリであるipaをごにょごにょしてplistファイルを取り出し中身を見てやろうっていうことをブラウザ単体でできるかという取り組みです。
関連記事というか、下準備の記事がこちらです。
ipaファイルを指定する
ipaファイルはHTMLのinput要素で指定させます。↓の例ではwebkitdirectory directory
をつけているのでフォルダ指定になっています。
<form action="#"> <input type="file" id="file-input" webkitdirectory directory /> <input type="button" id="button-start" value="plist解析" /> </form>
このHTMLによりこういうフォームができます。ipaファイルが入っているフォルダを指定して、plist解析
ボタンにより処理をスタートさせる作りにしておきました。
ipaファイルを展開する
ipaファイルはzip形式で圧縮されています。zip.jsというJavascriptがライブラリがあり、これを使えばブラウザ上でファイルを展開して色々ごにょごにょできるようになっています。
デモ(Read a zip file demo)を参考に展開部分を書いてみました。
inputからファイルの情報を得る
var fileInput = document.getElementById("file-input"); var file=fileInput.files[0]; // fileはipaファイルの情報を持っている
展開する
model.getEntries(file, function(entries) { entries.forEach(function(entry) { // entry が展開後の中身 }); });
modelっていうオブジェクトが急にでてきました。zip.jsのサンプルから持ってきたもので、zip.jsを使う関数を持っているオブジェクトです。単に使うだけならわざわざこんな別のオブジェクトを用意する必要はなく、普通に関数にでもしておけばいいかと思います。
var model = (function() { var URL = obj.webkitURL || obj.mozURL || obj.URL; return { getEntries : function(file, onend) { zip.createReader(new zip.BlobReader(file), function(zipReader) { zipReader.getEntries(onend); }, onerror); } }; })();
getEntries
関数では、zip.jsのzip.createReader
によって渡したファイルを展開してコールバックに要素を渡してくれるという風になっています。
plistを解析する
plistを特定する
ipaファイルをgetEntries
によって展開すると中身のコレクションが得られるので、その中からplistを特定します。ここは単純に文字列比較を用いました。
model.getEntries(file, function(entries) { entries.forEach(function(entry) { if(!entry.filename.match("app/Info.plist")){ return; } // entry は Info.plistファイル } });
plistの中身を得る
これでplist以外のものを除外できました。次にやることはplistを内容を取得することです。ここでもzip.jsのインターフェースを使います。
サンプルコードにおけるzip.js呼び出し用のオブジェクトmodel
にgetEntryFile
という関数がありました。それを少し改変し、与えたファイルの内容をバイナリで得られるようにしました。
得られたバイナリデータはonendコールバックに渡して処理します。
getEntryFile : function(entry, onend, onprogress) { var writer = new zip.BlobWriter(); entry.getData(writer, function(data) { onend(data); }, onprogress); }
model.getEntryFile(entry, function(data) { // data にplistの中身が入っている }, null);
plistのバイナリデータを解析する
あとはbplistParserを使ってplistを解析しJSONにするだけです。これは昨日の記事で紹介したライブラリを使うことで実現できます。
binary plist parser for Javascript (non-Node) - PILOG
parseFile
のコールバックにjsonが渡ってくるのであとはそれを好きなように使えばOK。
model.getEntryFile(entry, function(data) { var fileReader = new FileReader(); fileReader.onload = function() { bplist.parseFile(this.result, function(e, json){ if(e) throw e; onComplete(json); }); }; fileReader.readAsArrayBuffer(data); }, null);
ブラウザ単体でipaを展開してplistを解析するという話でした。
動くサンプルはこちら。