ionic(cordova) iOSでのtwitterログインで403 Forbidden の対応

はじめに

アプリのコードいじってないのにアプリで実装していたTwitterログインができなくなった。

使っていたプラグインはこちら
https://github.com/ManifestWebDesign/twitter-connect-plugin

エラー内容

error: Request failed: forbidden (403)
Error Domain=TWTRNetworkingErrorDomain Code=-1011 "Request failed: forbidden (403)" UserInfo={NSErrorFailingURLKey=https://api.twitter.com/oauth/request_token, NSLocalizedDescription=Request failed: forbidden (403), NSLocalizedFailureReason=Twitter API error :
<?xml version="1.0" encoding="UTF-8"?><errors><error code="415">Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings</error></errors> (code (null))}
原因

https://apps.twitter.com/
こちらの画面から設定する「Callback URLs」が今までアプリから使用する際は適当な値(http://example.com とか)をセットしていた。が、これにちゃんとした値をセットしないとダメになったというのが原因だった。じゃあアプリから呼び出す際には何をセットすればいいのか?というのでハマった。

対応

https://another.rocomotion.jp/15293882415732.html
こちらのページに救われた。以下をそれぞれ設定する必要がある

Callback URLs (Twitterアプリの設定画面)

twitterkit-xxxxxxx:// (xxxxxxxはtwitterアプリのConsumerKey)

info.plistに以下を追加(Xcode)

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>twitterkit-xxxxxxx</string>
    </array>
  </dict>
</array>
・・・
<key>LSApplicationQueriesSchemes</key>
<array>
  <string>twitter</string>
  <string>twitterauth</string>
</array>

swiftとかで開発していたらこれでOKだけれどもCordovaの場合、プラグイン自体がそのまま使えなかったのでプラグイン自体対応が必要だった。まず、上記のURLから取得したTwitterKitのSDKが古いぽくて動かなかった。Forkしてるリポジトリを探しているとちゃんとSDKも更新してくれてる人がいたのでそれを更にForkしてちょこっといじって解決。上記で書いたinfo.plistへの追記もプラグインが勝手にやってくれる。

そのまま使えるプラグインがこちら
GitHub - nrikiji/twitter-connect-plugin: Cordova/PhoneGap plugin to use Twitter Single Sign on

インストール

$ ionic plugin add https://github.com/nrikiji/twitter-connect-plugin --variable FABRIC_KEY=<Fabric API Key> --variable TWITTER_KEY=<Twitter Consumer Key> --variable TWITTER_SECRET=<Twitter Consumer Secret>

loginとlogoutしか実装されてないので画像の取得とかは必要なら実装しないとならない。以上です

【Android Studio】layoutディレクトリ追加

手動で作成する機会ってあまりないのだろうか

1. resディレクトリで右クリック > New > Android resource directory

f:id:yoppy0066:20180618224650p:plain

2. Resource typeをlayoutにあわせてAvailable qualifiersからCountry Codeを追加

f:id:yoppy0066:20180618224709p:plain

3. Mobile coutry codeに440を入力してOKボタン

f:id:yoppy0066:20180618224724p:plain

4. layoutディレクトリが追加された

f:id:yoppy0066:20180618224741p:plain

以上です

cordova-androidで生成したプロジェクトにSupport Libraryを追加

cordova-androidのバージョンは7.1

プロジェクト作成

$ cordova-android/bin/create android_demo test.android_demo

Gradle Scripts > build.gradle (Module: app)

dependencies {
    implementation fileTree(include: '*.jar', dir: 'libs')
    // SUB-PROJECT DEPENDENCIES START
    implementation project(path: ':CordovaLib')
    // SUB-PROJECT DEPENDENCIES END
}

dependencies {
    implementation fileTree(include: '*.jar', dir: 'libs')
    // SUB-PROJECT DEPENDENCIES START
    implementation 'com.android.support:design:26.1.0'       # ★追加
    implementation 'com.android.support:appcompat-v7:26.1.0' # ★追加
    implementation project(path: ':CordovaLib')
    // SUB-PROJECT DEPENDENCIES END
}

以上です

phpでローカルでwebサーバーを起動して別端末からアクセスする

macでのみ検証した。ビルドインwebサーバーというらしい。あくまで開発支援のための機能なので本番では使わないでねってマニュアルに書いてあった。

同じ端末からのみアクセスする

# サーバー起動
$ php -S localhost:8080 -t path/to/document_root

別端末からもアクセスする

# 自分のip調べる(grepは適当)
$ ifconfig | grep 192
    inet 192.168.1.110 netmask 0xffffff00 broadcast 192.168.1.255

# サーバー起動
$ php -S 0.0.0.0:8080 -t path/to/document_root

http://192.168.1.110:8080 でアクセスできるようになる。スマホからもみれるし手軽なのがいいね。以上です。

【Javascript】contenteditableなdivでカーソル位置が指定できなかった原因

contenteditableなdivに「今日はいい天気だ」というテキストが存在して「は」の後ろ(前から3文字目)にカーソルを置きたかった。以下のようなコードで実験したけどなぜかカーソルが先頭にきてしまった。

<div id="editor" contenteditable="true">
  今日はいい天気だ
</div>
<script>
window.onload = function() {
    var editor = document.getElementById('editor')
    var selection = window.getSelection()
    var range = document.createRange()
    range.setStart(editor.firstChild, 3)
    range.collapse(true)
    selection.removeAllRanges()
    selection.addRange(range)
    editor.focus()
}
</script>

原因は改行コードとスペースが含まれていたからそこも含めた位置だったというオチだった。。

<div id="editor" contenteditable="true">今日はいい天気だ</div>

ちなみにブラウザからスペースを挿入すると「 」が挿入されるので表示もスペースで表示される。以上です

【Javascript】iOSでblur時にSelection.rangeCountが取得できなかったときに調べたこと

今回やりたかったのはfocusが外れるときの要素を保存しておき、再びfocusがセットされるときにカーソル位置を戻すということ

試したのはこんなコード

<div id="editor" contenteditable="true"></div>
<input type="button" id="restore-range" value="restore range" />

<script>
var saveRange
$('#editor').on('blur', function() {
  var s = window.getSelection()
  if (0 < s.rangeCount) {
    saveRange = s.getRangeAt(0)
  }
})

$('#restore-range').on('click', function() {
  if (saveRange) {
    var s = window.getSelection()
    if (0 < s.rangeCount) {
      s.removeAllRanges()
    }
    s.addRange(range)
  }
})
</script>

PC版のChromeAndroid端末では期待通りに動くものの、iOS では s.rangeCount の部分が0のため動かず。
iOSではwindow.getSelection().rangeCount や getRangeAtが使えないのかと困っていたが以下のコードだとちゃんと取得できる。

$('#editor').on('mousedown mouseup keydown keyup', function() {
  var s = window.getSelection()
  if (0 < s.rangeCount) {
    range = s.getRangeAt(0)
  }
})

きっとblurの前に更新されてしまうのだろうという想像。どのタイミングがベストかわからないけどとりあえず上記のコードでやりたいことはできるかな。以上です

【cordova】cordovaFileTransfer で params も付けてファイルアップロード

ngCordovaの$cordovaFileTransferの使い方メモ
https://github.com/apache/cordova-plugin-file-transfer のラッパー

$cordovaFileTransfer.upload(
  'https://xxx.yyy.zzz/path/to/api'
  'path/to/upload_file', {
    fileKey: 'image',   // アップロードするファイル名
    httpMethod: 'POST',
    headers: {          // 任意のHTTPヘッダー
      header1: 'xxxxxx',
      header2: 'xxxxxx'
    }
    params: {           // 任意のパラメータ
      param1: 'xxxxx',
      param2: 'xxxxx',
    }
  }
).then(function() {
  // success
}).catch(function(err) {
  // failed
})

以上です