【ionic3】iOSでvideoインライン再生

ionic3でvideoタグのインライン再生しようとしたら上手くいかなかったのでそのときのメモ

HTMLはこんな感じ

<video muted="true"                                                                                                                                                                                                
       preload="auto"                                                                                                                                                                                              
       webkit-playsinline playsinline controls                                                                                                                                                                     
       src="assets/imgs/sample.mp4">                                                                                                                                                                               
</video>

調べてみると wkwebview の設定で allowsInlineMediaPlayback という設定があった。
CDVWKWebViewEngine.m を見てると allowsInlineMediaPlayback を設定している箇所もあった。

config.xml

<preference name="AllowInlineMediaPlayback" value="true" />

これだけでした。以上です

【Ionic3(Angular)】Componentを作成してHTMLを分割する方法まとめておく

はじめに

今回やりたかったことは以下のようなコードの「リスト」の部分が複雑になったので別ファイルに分けたいということでした。AngularのComponentを作成すれば実現できるようでIonicコマンドでComponentを作成できるのでこちらの使い方をメモしておく。

<ion-content>
  <!-- タイトル -->
  <div>Title</div>

  <!-- リスト -->
  <ion-list>
    <ion-item>Item1</ion-item>
    <ion-item>Item2</ion-item>
    ・・・
  </ion-list>

</ion-content>

やりたいことは以下
・ファイルを分割したい
・ionicのコンポーネントを使いたい
・呼びだし側と呼ばれる側とで値を共有したい

実装

Componentを作成

$ ionic g component mylist

src/componentsディレクトリが作成されてひな形が作成される

components.module.ts

import { NgModule } from '@angular/core';
import { MyListComponent } from './my-list/my-list';

@NgModule({
  declarations: [MyListComponent],
  imports: [],
  exports: [MyListComponent]
})

export class ComponentsModule {}

さらに src/components/my-list ディレクトリも作成されて html、scss、tsファイルのひな形が作成される。これをアプリから呼びだすことができるようにapp/app.module.tsに以下を追記

app.module.ts

・・・
import { ComponentsModule } from '../components/components.module' // ★追記
・・・

@NgModule({
  ・・・
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    ComponentsModule, // ★追記
  ]
})

これで追加したmy-listコンポーネントを以下の形でよびだせるようになる。

<ion-content>
  <!-- タイトル -->
  <div>Title</div>

  <!-- リスト -->
  <my-list></my-list>

</ion-content>

Ionicコンポーネントを呼びだせるようにする

続いてmy-listコンポーネント実装していく。ionicのコンポーネント(ion-list)を使いたいのでcomponents.module.tsにIonicModuleを追記

・・・
import { IonicModule } from 'ionic-angular' // ★追記
・・・
@NgModule({
  declarations: [MyListComponent],
  imports: [IonicModule],
  exports: [MyListComponent]
})

components/my-list/my-list.html

<ion-list>
    <ion-item>Item1</ion-item>
    <ion-item>Item2</ion-item>
    ・・・
</ion-list>

呼び出し側と呼ばれる側とで値を共有する

値の共有の例として以下を実装する
・ion-listに表示する値をコンポーネントに渡す
・ion-listでクリックされた行を親に渡す

AngularのngIf、ngForを使えるようにする

追加したComponentでAngularのngIfやngForを使いたい場合はこれらも使えるようにBrowserModuleを追加する必要がある。

components/components.module.ts

import { BrowserModule } from '@angular/platform-browser';
・・・

@NgModule({
  ・・・
  imports: [BrowserModule, IonicModule],
  ・・・
})
コンポーネントに値を渡す(コンポーネントが値を受け取る)

受け取る側

components/my-list/my-list.ts

import { Component, Input } from '@angular/core';

・・・

export class MyListComponent {

  @Input() items: any

}

component/my-list/my-list.html

<ion-list>
  <ion-item *ngFor="let item of items">{{ item.name }}</ion-item>
</ion-list>

渡す側

xxx.ts

export class Hoge {

  items: any = [
    { id: 1, name: "Item1"},
    { id: 2, name: "Item2"},
    ・・・
  ]

}

html

<ion-content>
  <!-- タイトル -->
  <div>Title</div>

  <!-- リスト -->
  <my-list [items]="items"></my-list>

</ion-content>
コンポーネントから値を受け取る

渡す側

components/my-list/my-list.ts

import { Component, Output } from '@angular/core';

・・・

export class MyListComponent {

  @Output() selected = new EventEmitter<number>()

  ・・・

  select = (id: number) => {
    this.selected.emit(id)
  }

}

component/my-list/my-list.html

<ion-list>
  <ion-item *ngFor="let item of items" (click)="select(item.id)">{{ item.name }}</ion-item>
</ion-list>

受け取る側

xxx.ts

export class Hoge {

  select = (id) => {
    console.log(id)
  }

}

html

<ion-content>
  <!-- タイトル -->
  <div>Title</div>

  <!-- リスト -->
  <my-list (selected)="select($event)"></my-list>

</ion-content>

ずらずら書いたけど以上です。

Ionic3とAngularのバージョン確認

IonicはCLIフレームワークとでそれぞれバージョン違うし。Angularはバージョンどんどん上がってる印象なので。自分がそれぞれどのバージョン使ってるかわからなくなってきた。

CLIのバージョン

$ ionic -v
3.20.0

FWのバージョンはpackage.jsonを見るとわかる

{
  ・・・

  "dependencies": {
    "@angular/animations": "5.2.11",
    "@angular/common": "5.2.11",
    "@angular/compiler": "5.2.11",
    "@angular/compiler-cli": "5.2.11",
    "@angular/core": "5.2.11",
    "@angular/forms": "5.2.11",
    "@angular/http": "5.2.11",
    "@angular/platform-browser": "5.2.11",
    "@angular/platform-browser-dynamic": "5.2.11",

    ・・・

    "ionic-angular": "3.9.2",

    ・・・
  },

  ・・・
}

Angularが5.2.11で、Ionicが3.9.2だった。以上です

CircleCI2、Fastaneでの2段階認証が設定されたアップルIDでのアプリアップロードを諦めた話

fastlaneのドキュメントに2段階認証のことものってた
https://docs.fastlane.tools/best-practices/continuous-integration/

環境変数 FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD に2段階認証の場合はAPPパスワードを発行してセットするように書いてあったのだがやってみてもうまくいかず。。

deliverでiTtunesConnectにアップロードしようとするところで、こんなエラーで落ちる。ソース追う気力もないけど2段階認証のところでなんかやろうとして落ちてる感じだ。

/Library/Ruby/Gems/2.0.0/gems/highline-1.7.10/lib/highline/question.rb:413:in `remove_whitespace': [!] undefined method `strip' for nil:NilClass (NoMethodError)
        from /Library/Ruby/Gems/2.0.0/gems/highline-1.7.10/lib/highline.rb:873:in `get_line'
        from /Library/Ruby/Gems/2.0.0/gems/highline-1.7.10/lib/highline.rb:891:in `get_response'
        from /Library/Ruby/Gems/2.0.0/gems/highline-1.7.10/lib/highline.rb:264:in `ask'
        from /Library/Ruby/Gems/2.0.0/gems/highline-1.7.10/lib/highline.rb:365:in `choose'
        from /Library/Ruby/Gems/2.0.0/gems/fastlane-2.61.0/spaceship/lib/spaceship/two_step_client.rb:35:in `handle_two_step'
        from /Library/Ruby/Gems/2.0.0/gems/fastlane-2.61.0/spaceship/lib/spaceship/client.rb:473:in `send_shared_login_request'
        from /Library/Ruby/Gems/2.0.0/gems/fastlane-2.61.0/spaceship/lib/spaceship/tunes/tunes_client.rb:111:in `send_login_request'

        (省略)

        from /usr/local/bin/fastlane:23:in `load'
        from /usr/local/bin/fastlane:23:in `<main>'

ドキュメントの冒頭に以下の記述があった

The easiest way to get fastlane running on a CI system is to create a separate Apple ID that doesn't have 2-factor auth enabled, with a long, randomly generated password. Additionally make sure the newly created Apple account has limited\
 access to only the apps and resources it needs.

「2段階認証を無効にしたApple IDを別途作成して、必要な権限を与えて使ってください」とのことでした。説明見てるとできそうだけど、時間かけてもあまり意味もないと思うので今回は諦めました。以上です

ionic(cordova) CircleCI2とFastlaneでiOSアプリをデプロイゲートにアップロードする手順まとめ

はじめに

今回やりたかったことは
・ionicで開発したiOSアプリをCircleCI2上でAdHoc版ビルド
・ビルドしたアプリをデプロイゲートへアップロード
・Fastlane Matchは使わず手元にある証明書とプロビジョニングプロファイルで行う
ビルドとアップロードはFastlaneというツールを使う

必要なもの
・証明書
キーチェーンアクセスから書き出す「iPhone Distribution:xxxxxxxxxxx(xxxxxx)」いつものp12ファイル。
・プロビジョニングプロファイル
・デプロイゲートのAPIキーとアカウント名

流れ

CircleCI上で証明書等を予め登録しておく
・証明書とプロビジョニングプロファイルをCircleCI上に暗号化して登録(環境変数を利用)
・デプロイゲートのアカウントとAPIキーもCircleCI上に登録(環境変数を利用)
https://circleci.com/gh/[githubアカウント]/[リポジトリ名]/edit#env-vars
↑ここから登録できる

以下を用意
・.circleci/config.yml
・fastlane/Fastfile

イメージとしては普段macでおこなっている作業をCircleCI上のmacで行うだけ。
・cordova、ionic と依存するnode_modulesのインストール
・予め登録した証明書とプロビジョニングプロファイルを復号化してマシンにインストール
・インストールした証明書等を使ってアプリをビルド
・予め登録したデプロイゲートの情報を使って、デプロイゲートへアップロード

ハマったこと

証明書とプロビジョニングプロファイルを正しく指定してるのにSigning Errorが消えない

エラー

Code Signing Error: Signing for "circleci_demo" requires a development team. Select a development team in the project editor.
Code Signing Error: Code signing is required for product type 'Application' in SDK 'iOS 11.2'

xcodeでいうところの「Automatically manage signing」がONになっている状態だとエラーになってしまっていた。
ONが奨励されてる?のかわからないけど今回はこれをOFFにすることで解決した。
後述するFastlane の disable_automatic_code_signing メソッドを使うとOFFになる。

cordova-iosが生成するxcodeの project.pbxproj ファイルの形式が不完全

エラー

Seems to be a very old project file format - please open your project file in a more recent version of Xcode

TargetAttributes属性がないとFastlaneがこのエラーで終了してしまう。
Cordovaで生成した直後のプロジェクトだとこの属性がないらしい(最新のcordova-iosでは改善してるかも)
で、platforms/ios/circleci_demo.xcodeproj/project.pbxproj もgitで管理してビルドする前にこのファイルを使うことで解決することにした。

アーカイブに成功してエクスポートでエラー

エラー

Exit status: 70
No provisioning profile provided
Make sure to pass a valid provisioning for each required target
Check out the docs on how to fix this: https://github.com/fastlane/fastlane/tree/master/gym#export-options

よくわかってないのだが、xcodebuildでのアーカイブで出力されるplistをエクスポートの際に使用するようなのだが、それが正しくないらしい。スタックオーバーフローとか見てると、xcode上でエクスポートする際に作られるExportOptions.plistを使うと良いらしい。これもGitで管理するようにしてFastfileで指定することで解決した。gymのexport_optionsで指定可能でした。

実装

証明書とプロビジョニングプロファイルをCircleCI2に登録
$ base64 -i xxxxx.p12 | pbcopy
$ base64 -i xxxxx. mobileprovision | pbcopy

こちらのページに細かく書かれている(というかまんま)
http://developabout0309.blogspot.com/2018/05/circleci20fastlanefabric_1.html

今回は以下の変数名で登録した
CERTIFICATES : pm12ファイル
PROVISIONING_PROFILES : プロビジョニングプロファイル
DEPLOYGATE_USER : デプロイゲートのアカウント
DEPLOYGATE_API_KEY : デプロイゲートのAPIキー

.circleci/config.yml
version: 2
jobs:
  build:
    macos:
      xcode: "9.2.0"
    shell: /bin/bash --login
    working_directory: ~/workspace
    steps:
      - checkout
      - run:
          name: install ionic
          command: |
            # Ionicインストール
            npm install -g cordova@6.5.0
            npm install -g ionic@2.2.3                                                                                                                                                                             
            npm install                                                                                                                                                                                            
                                                                                                                                                                                                                   
            # 最新のcordova-iosでプロジェクト作成                                                                                                                                                                  
            ionic platform rm ios                                                                                                                                                                                  
            ionic platform add ios@4.5.4                                                                                                                                                                           
            ionic prepare                                                                                                                                                                                          
      - run:
          name: build and upload deploygate
          command: |
            # stagingブランチの場合、デプロイゲートへアップロード
            if [ "${CIRCLE_BRANCH}" == "staging" ]; then                                                                                                                                                           
              # 証明書をデコード
              base64 -D -o circleci_demo.p12 <<< $CERTIFICATES                                                                                                                                                     
                                                                                                                                                                                                                   
              # プロビジョニングプロファイルのインストール                                                                                                                                                         
              mkdir -pv ~/Library/MobileDevice/Provisioning\ Profiles/                                                                                                                                             
              base64 -D -o ~/Library/MobileDevice/Provisioning\ Profiles/CircleCI_Adhoc.mobileprovision <<< $PROVISIONING_PROFILES                                                                                 
                                                                                                                                                                                                                   
              # xcodeprojファイルをチェックアウト                                                                                                                                                                  
              git checkout platforms/ios/circleci_demo.xcodeproj/project.pbxproj                                                                                                                                   
                                                                                                                                                                                                                   
              # AdHocビルド                                                                                                                                                                                        
              fastlane ios build                                                                                                                                                                                   
                                                                                                                                                                                                                   
              # デプロイゲートへアップロード                                                                                                                                                                       
              fastlane ios upload_deploygate                                                                                                                                                                       
                                                                                                                                                                                                                   
            # masterブランチの場合、AppStoreへアップロード                                                                                                                                                         
            elif [ "${CIRCLE_BRANCH}" == "master" ]; then                                                                                                                                                          
            fi                                                                                                                                                                                                     
fastlane/Fastfile
platform :ios do
  desc "Build for iOS"
  lane :build do
    if is_ci?
      setup_circle_ci
      import_certificate(
        keychain_name: ENV["MATCH_KEYCHAIN_NAME"],
        keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"],
        certificate_path: 'circleci_demo.p12',
        certificate_password: ''
      )
    end
    update_app_identifier(
      xcodeproj: "platforms/ios/circleci_demo.xcodeproj",
      plist_path: "circleci_demo/circleci_demo-Info.plist",
      app_identifier: 'ciecleci.test'
    )
    disable_automatic_code_signing(
      path: "platforms/ios/circleci_demo.xcodeproj"
    )
    gym(
      scheme: 'circleci_demo',
      workspace: 'platforms/ios/circleci_demo.xcworkspace',
      configuration: 'Debug',
      export_method: "ad-hoc",
      clean: true,
      verbose: true,
      output_directory: "build",
      output_name: "circleci_demo",
      xcargs: "OTHER_SWIFT_FLAGS='$(inherited) -DSTGING' PROVISIONING_PROFILE_SPECIFIER='CircleCI Adhoc' CODE_SIGN_IDENTITY='iPhone Distribution'",
      export_xcargs: "-allowProvisioningUpdates",
      export_options: "fastlane/ExportOptions.plist"
    )
  end
  desc "Upload To Deploygate"
  lane :upload_deploygate do
    deploygate(
      api_token: ENV["DEPLOYGATE_API_KEY"],
      user: ENV["DEPLOYGATE_USER"],
      ipa: "build/circleci_demo.ipa"
    )
    sh "rm -rf ../build"
  end
end

こんなもんかな。以上です。

シンボリックリンクを相対パス指定で作る

基本

$ ln -s 実際のパス リンク

こんなファイル構成でdir2/aaa.txtにdir1/aaa.txtへのシンボリックリンクを貼りたい

dir1/aaa.txt
dir2

これでいけると思ったらNG

$ ln -s dir1/aaa.txt dir2/aaa.txt

これならOK

$ ln -s ../dir1/aaa.txt dir2/aaa.txt

リンクからの相対パスを指定しないとダメなのか。たまにしかやらないから忘れる。以上です。

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しか実装されてないので画像の取得とかは必要なら実装しないとならない。以上です