パルカワ2

最近はFlutterをやっています

Flutter+Android Studio 3.4.1 で Adaptive icons が設定できない

iOSでつくったものをAndroidで作り始めると「マジめんどいので共通化したい」という気持ちが芽生えるので、やりはじめた。 www.appbrewery.co

こういう環境でやっている。

Android Studio 3.4.1
Build #AI-183.6156.11.34.5522156, built on May 2, 2019
JRE: 1.8.0_152-release-1343-b01 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.14.5

「How to Add App Icons to the iOS and Android Projects」を見ていてAndroidのAdaptive icons対応するところで、 android/app/src/main/res を右クリックして、 New > Image Assets を選んだらええで!って言われたけど、Project must be built with SDK 26 or later to use adaptive icons と言われてNextが押せない。SDKが26未満なの〜?マジ〜?と思って確認してみたところ、28を使っているので問題ないようだった。

f:id:hisaichi5518:20190621225356p:plain なんかよくわからないけどAndroid Studioが認識出来ていないのかなーと思って、build.gradleを編集しているときに右上に出ているOpen for Editing in Android Studioをクリックして、androidディレクトリをAndroid StudioをNew Windowで開き、再度同じ手順でやったら出来た。 f:id:hisaichi5518:20190621225351p:plain

Jestを使うことにした

Jest · 🃏 Delightful JavaScript Testing

  • ユニットテスト書きたい
  • DOM操作があるテストができる
  • 通信の処理があるのでモックとかもしたい
  • 導入がめんどくさくない

自分でkarma/jasmineの設定もしてみて先人の知恵のおかげで困りはしなかったんだけど、まあJestでええか…みたいな感じになった。

Jest+TypeScriptでDOMを操作するテストを書く

ここに書かれてる方法だと document がないよ!って言われる
DOM Manipulation · Jest
JSDOMでやってあげるとよさそう。

// Hoge.test.ts
import {JSDOM} from "jsdom";

declare global {
    namespace NodeJS {
        interface Global {
            document: Document
        }
    }
}

test('js dom', () => {
    global.document = new JSDOM(`<span id="username">yoshitaka-yuriko</span>`).window.document;
    expect(document.querySelector(`#username`).textContent).toBe("yoshitaka-yuriko")
});

ngrok を使う

自分向けにローカルにあるJSをhttps経由で配布したいが、自分であれこれ設定するのはだるい。ngrokというのがあるらしいので使ったらすぐできた。

ngrok は登録が必要で、登録するとコマンドのインストールや設定を促される。そのあと以下を実行するとよい

ngrok http 8000 -bind-tls=true

内容も瞬時に反映されるので便利 ちなみに手元のサーバはファイル配信のみなのでWebServer for Chromeを使った。

これが本来の用途っぽい?

api.slack.com

TypeScript の async/await

雰囲気でPromiseを使っていたが、雰囲気でTypeScriptを使い始め、雰囲気でasync/awaitを使い始めたが、よくわからないままだったので簡単に自分向けにまとめておく。 間違えていたら教えてほしい。ちなみにTSのtargetはes6

async をつけると

Promiseが返るようになるという認識

返り値

Promise.resolve() を返すかそのまま値を返すとよい。 Promise.resolve() が必要ないならわざわざラップして返す必要はなさそう。

 const t = async () => {
     return Promise.resolve("ok")
 };
 async function main() {
     await t().then(console.log);
     console.log("finish")
 }
 main();
 const t = async () => {
     return "ok"
 };
 async function main() {
     await t().then(console.log);
     console.log("finish")
 }
 main();
   const t = async () => {
       // returnしなくても次に進む
   };
   async function main() {
       await t().then(console.log);
       console.log("finish")
   }
   main();

エラーハンドリング

Promise.reject() を返すかthrowすればエラーが起きたことを知らせることが出来る。 try-catchを利用するので、エラーが起きた場合はthrowするのがわかりが良い気がする。

 const t = async () => {
     return Promise.reject(new Error("error!"))
 };
 async function main() {
     try {
       await t().then(console.log);
     } catch (error) {
         console.log("catch error", error)
     } finally {
       console.log("finish")
     }
 }
 main();
 const t = async () => {
     throw new Error("error!")
 };
 async function main() {
     try {
       await t().then(console.log);
     } catch (error) {
         console.log("catch error", error)
     } finally {
       console.log("finish")
     }
 }
 main();

また以下のようにthrowしただけであってもPromiseのcatchを使うことが可能である。 catchした場合は、try-catchのcatchには入らず、通常処理に戻る

  const t = async () => {
      throw new Error("error!")
  };
  async function main() {
      try {
        await t().catch(console.log)
        console.log("age") // 実行される
      } catch (error) {
          console.log("catch error", error)
      } finally {
        console.log("finish")
      }
  }
  main();

errorはなにも返さなくてもよい。 例えば Promise.reject() に何も渡さない場合catchされた error は undefined になる。エラーが起きたわけではないけど、なんらかの理由でこれ以上処理を進めたくない場合などに使うらしい。なるほど(Promiseのテクニック??)

 const t = async () => {
     return Promise.reject();
 };
 async function main() {
     try {
         await t()
         console.log("age") // 実行されない
     } catch (error) {
         console.log("catch error", error)
     } finally {
         console.log("finish")
     }
 }
 main();

個人的にはそれをやるならそれ用のエラーを作ったほうが明確でよいと思ったが好みかもしれない。

 class AbortError extends Error { 
 }
 const t = async () => {
     return Promise.reject(new AbortError("ほげほげだからAbortだよ"));
 };
 async function main() {
     try {
         await t()
         console.log("age")
     } catch (error) {
         if (error.constructor === AbortError) {
             console.log(error.message)
             return
         }
         console.log("catch error", error)
     } finally {
         console.log("finish")
     }
 }
 main();

HTMLにあるフォームをsubmitするのではなくfetchを使ってsubmitしたい

form.submit()するんじゃなくてfetchを使う必要があったのでやり方調べたらFromDataなるものがあった。便利

const form = document.querySelector("#form1");
form.querySelector(`input[name="hoge"]`).value = "hoge";
const data = new FormData(form);

fetch("...", {
    "credentials":"include",
    "headers":{
        "accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "accept-language":"ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7",
        "cache-control":"max-age=0",
        "content-type":"application/x-www-form-urlencoded",
        "upgrade-insecure-requests":"1"
    },
    "body": data,
    "method":"POST",
    "mode":"cors"
}).then(res => res.text()).then(body => {
   // はい
})

FormData オブジェクトの利用 - ウェブデベロッパーガイド | MDN
FormData - Web API | MDN