カテゴリーアーカイブ iOS

村上 著者:村上

【Cordova】create-react-appコマンドでCordovaアプリの開発環境を作る

今更感はありますが…備忘録としてまとめ。
タイトル通り、create-react-app コマンドと cordova のコマンドを使って、Cordova アプリの開発環境を作る方法です。
色々な記事がありましたが、個人的に一番良いと思ったのがこちらの Qiita の記事です。

Create React App & Cordovaでアプリをつくる環境を整える 2018年4月時点 – Qiita
https://qiita.com/bathtimefish/items/113154e89650b351b5b7

 

作成方法ですが、まずは create-react-appcordova をインストールします。

npm install -g create-react-app
npm install -g cordova

インストールが終わったら、任意の場所で下記のコマンドを実行します。

create-react-app [プロジェクト名]
cd [プロジェクト名]
npm run eject 

こちらのコマンドを実行すると、Create React App プロジェクトが作成できます。

3行目のコマンドは、react-scripts をディレクトリに展開するとのことでしたが…よく分かりませんでした。
なお、こちらを実行すると、? Are you sure you want to eject? This action is permanent. (y/N) と聞かれるので、問題なければ y を入力します。

上記のコマンドが完了したら、config/paths.js を開きます。
こちらのファイルに、appBuild: resolveApp('build') という記述があるので、ここを appBuild: resolveApp('www') に変更します。
次に package.json を開き、"homepage": "./", を追加します。
追加する場所は、"dependencies": { …… }, のすぐ上あたりです。

上記が全て完了したら、一旦一つ上のディレクトリに戻り、下記コマンドで cordova の環境を作成します。

cordova create [ディレクトリ名] [Bundle identifier/アプリケーションID] [プロジェクト名]

なお、ディレクトリ名は create-react-app コマンドで指定したプロジェクト名とは異なるものを指定してください。

こちらを実行したら、このプロジェクト内の config.xml を、上で作成した Create React App プロジェクトのディレクトリの直下にコピーします。

public/index.html を開き、下記の 3行を head 内に追加します。

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">

なお、1行目の meta http-equiv="Content-Security-Policy" は環境にあわせて適宜変更してください。

そして、同じく Create React App プロジェクト の src/index.js を下記のように修正します。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

const startApp = () => {
  ReactDOM.render(<App />, document.getElementById('root'));
  registerServiceWorker();
};

if(window.cordova) {
  document.addEventListener('deviceready', startApp, false);
} else {
  startApp();
}

なおこのままビルドすると、上記のコードにある registerServiceWorker.js がなくてエラーになるので、src ディレクトリ内に下記の内容で作成します。

// In production, we register a service worker to serve assets from local cache.

// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.

// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.

const isLocalhost = Boolean(
  window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

export default function register() {
  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return;
    }

    window.addEventListener('load', () => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

      if (isLocalhost) {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl);

        // Add some additional logging to localhost, pointing developers to the
        // service worker/PWA documentation.
        navigator.serviceWorker.ready.then(() => {
          console.log(
            'This web app is being served cache-first by a service ' +
              'worker. To learn more, visit https://goo.gl/SC7cgQ'
          );
        });
      } else {
        // Is not local host. Just register service worker
        registerValidSW(swUrl);
      }
    });
  }
}

function registerValidSW(swUrl) {
  navigator.serviceWorker
    .register(swUrl)
    .then(registration => {
      registration.onupdatefound = () => {
        const installingWorker = registration.installing;
        installingWorker.onstatechange = () => {
          if (installingWorker.state === 'installed') {
            if (navigator.serviceWorker.controller) {
              // At this point, the old content will have been purged and
              // the fresh content will have been added to the cache.
              // It's the perfect time to display a "New content is
              // available; please refresh." message in your web app.
              console.log('New content is available; please refresh.');
            } else {
              // At this point, everything has been precached.
              // It's the perfect time to display a
              // "Content is cached for offline use." message.
              console.log('Content is cached for offline use.');
            }
          }
        };
      };
    })
    .catch(error => {
      console.error('Error during service worker registration:', error);
    });
}

function checkValidServiceWorker(swUrl) {
  // Check if the service worker can be found. If it can't reload the page.
  fetch(swUrl)
    .then(response => {
      // Ensure service worker exists, and that we really are getting a JS file.
      if (
        response.status === 404 ||
        response.headers.get('content-type').indexOf('javascript') === -1
      ) {
        // No service worker found. Probably a different app. Reload the page.
        navigator.serviceWorker.ready.then(registration => {
          registration.unregister().then(() => {
            window.location.reload();
          });
        });
      } else {
        // Service worker found. Proceed as normal.
        registerValidSW(swUrl);
      }
    })
    .catch(() => {
      console.log(
        'No internet connection found. App is running in offline mode.'
      );
    });
}

export function unregister() {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.ready.then(registration => {
      registration.unregister();
    });
  }
}

作成が終わったら、Create React App プロジェクトのディレクトリに移動し、npm run build を実行します。
エラーが出なければビルド成功です!

あとは、任意のプラットフォームを、下記のコマンドを使って追加してください。

cordova platforms add browser
cordova platforms add android
cordova platforms add ios

もちろん全部追加しなくてもOKです。

あとは cordova のコマンドを使ってプロジェクトを実行してください。
下記のコマンドを実行すると、ブラウザで実行できます。

cordova run browser

 

以上、create-react-app コマンドを使って Cordova アプリの開発環境を作る方法でした。
ほぼ Qiita の参考記事そのままなので、こちらを参考にして頂いても大丈夫です。

  • この記事いいね! (0)
村上 著者:村上

【iOS】MacからiPhoneに写真を転送する方法

iPhone から Mac に写真を転送するのは特に難しくなかったのですが、その逆が少しややこしかったので、備忘録としてまとめ。
いくつか方法があるようでしたが、転送ソフトとかをわざわざ入れるのは面倒だったので、今回紹介するのは iTunes を利用する方法についてです。

今回参考にした記事はこちらから。

【完全版】迅速にMacからiPhoneに写真を転送する7つの方法
https://www.imobie.jp/support/transfer-mac-photos-to-iphone.htm

 

まず、事前準備として、転送したい写真を一つのディレクトリに格納し、分かりやすい場所に置いておきます。
ディレクトリの名前は日本語でも問題なく、場所もデスクトップとかでOKです。

次に iPhone と Mac を接続し、iTunes を起動します。

上のスクリーンショットの通り、接続した iPhone を選択してから、サイドバーメニューから「写真」を選択します。
次に、「写真を同期」にチェックを入れ、すぐ下の欄の「写真のコピー元」から、先程作成したディレクトリを選択します。
あとは、右下の「適用」ボタンを選択すれば、iPhone に写真が転送されます。

操作としては以上です!
「写真のコピー元」を選択する際には写真ファイル自体は選択できないので、ディレクトリに写真を格納するのがポイントですね。
転送ソフトを使わないと手順が多くて面倒になるかと思いましたが、思ったよりも簡単でした。

 

以上、Mac から iPhone に写真を転送する方法でした。
ご参考になれば幸いです。

  • この記事いいね! (0)
takahashi 著者:takahashi

Google検索でARで動物を現実世界上に表示できる機能が利用可能に

最近のAR/VR周りの盛り上がりがかなりホットになってきていますが、そんな中、Google検索アプリにとても面白い機能が追加されました…!

Google検索アプリで動物を検索すると…

“実物大のイヌが目の前に迫ってきます。”

のようなとても興味をそそる表示が。

“3D表示”をタップすると

こんな画面になります。

“周囲のスペースに表示する”をタップすると…

殺伐とした(?)オフィスにワンちゃんが!!!

自分の好きな位置、向きにすることもできます。

シャッターボタンをタップすると写真を撮ることもできます。

他にも

ねこはもちろん、

ライオンや

鷹なども呼び出すことができます…!

このAR機能、実際に使ってみるとわかるのですが、一度空間を認識できると、結構ぐりぐり動かしても、3Dオブジェクトの動きも現実にかなり精密に追従するので、結構リアリティを感じることができますし、影もちゃんと地面を認識して描画されているのはすごいと感じました。

なにより、こういった普段動物園などに足を運ばないとお目にかかれない動物もじっくり見ることができるのは楽しいですね。

ポケモンGOのように、普段はありえない場所に動物をよびだして写真撮影してみるのも面白いかもしれないですね。

The app was not found in the store. 🙁
Google
Google
Developer: Google LLC
Price: Free
  • この記事いいね! (0)
村上 著者:村上

【iOS】iPhoneのホーム画面でアプリアイコンが一瞬チラつく時の対処法

アプリ検証用の社用端末(iPhone)でたまーに発生していたアイコンのちらつきとその対処法についてです。
今までも発生しておりましたが、支障はないので放置していました。
でも、メモリ不足とかだったら早めに対処したほうがいいか…と思い、調べてみました。
なお、端末は iPhone 6 Plus で、ソフトウェアバージョンは 12.3.1 です。

今回参考にさせていただいたサイトはこちらから。

iPhoneのアプリが勝手に点滅する!?壊れた!?よくあるご相談 | iPhone修理大阪 豊中市 吹田市 | スマートクール エトレとよなか店・イオン吹田店
https://smartcool-toyonaka.com/blog/7393/

 

で、上記の参考サイトによると、アイコンが勝手に点滅する原因は、iPhone の仕様とのこと。
アップデートがあるアプリを自動更新しようとしているため、一瞬アイコンが点滅するようです。
特にメモリ不足とか端末の不具合とかではないので、特に気にしなくてOKとのことでした。

ただ、どうしても気になる!という場合は、アプリの自動更新を OFF にしてください。
iPhone の設定の 一般 > Appのバックグラウンド更新 から設定ができます。
念のためスクリーンショットも載せておきます。

こちらの自動更新は、アプリごとに設定することもできます。
また、更新タイミングも「オフ」「Wi-Fi」「Wi-Fiとモバイルデータ通信」から選ぶことができますので、お好みで変更してください。

 

以上、iPhone のホーム画面のアプリアイコンが一瞬チラつく時の原因とその対処法でした。
端末自体に特に問題があるわけではなくて一安心でした。

  • この記事いいね! (0)
村上 著者:村上

【Xcode】「Error: Multiple commands produce」エラーの対処法

今回は Xcode で遭遇したエラーについて。
諸事情あって、Cordova で開発した iOS アプリを一度削除して、再度 iOS プラットフォームを追加し直したのですが、その際に「Error: Multiple commands produce」というエラーが発生しました。
GoogleService-Info.plist のファイルパスがエラーメッセージに含まれていたので確認したところ、またこのファイル内容がおかしくなっていたため正しいファイル内容と置き換えたのですが、やはり解決できず。

で、検索したところ、下記の Qiita の記事がヒットしました。

Xcode10 Error: Multiple commands produceを解決する – Qiita
https://qiita.com/SatoTakeshiX/items/047a313f564879e290ec

 

こちらの記事によると、古いビルドシステムに戻すことで解決できるとのことでした。
他のエラーでもお世話になった方法ですね。

Xcode のヘッダメニュー「File」から、「WorkSpace Settings…」をクリックします。
そうすると、下記のウィンドウが表示されるので、「Build System」を「Legacy Build System」に変更します。

あとは、通常通り Build > Run を実行します。
私の環境では、こちらの方法でエラーが解消できました!

なお、この方法はちょっと…という場合は、上で紹介した Qiita の記事に、新しいビルドシステムのままでエラーを解決する方法も掲載されているので、そちらを参考にしていただければと思います。

 

以上、Xcode で「Error: Multiple commands produce」エラーが発生した場合の対処法でした。
こちらの古いビルドシステムを使う方法は、他のエラーの解決方法としても紹介されていることがあるので、覚えておいて損はないはず。
また、少し古いプロジェクトを実行する場合は、先に変更しておいてもいいかもしれませんね。
ご参考になれば幸いです。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】「cordova-plugin-firebase-crashlytics」でFirebaseのCrashlyticsを導入

タイトル通り、Cordova で開発しているアプリに Google Firebase の Crashlytics を導入する方法です。
最初、Fabric がいいかな?と思ったのですが、こちらのサービスは Firebase と統合されるとのことでしたので、Firebase を使うことにしました。

GitHub のページはこちらから。

GitHub – ReallySmallSoftware/cordova-plugin-firebase-crashlytics: Google Firebase Crashlytics Cordova plugin
https://github.com/ReallySmallSoftware/cordova-plugin-firebase-crashlytics

 

インストールのコマンドは下記のとおり。

cordova plugin add cordova-plugin-firebase-crashlytics

GitHub に載っていたコマンドは cordova plugin add cordova-plugin-firebase-crashlytics --variable ANDROID_FIREBASE_CORE_VERSION=16.0.0 だったのですが、バージョンを指定しないとデフォルト値が指定されるとのことだったので省略しました。
特にインストール時にエラー等は発生しなかったので問題ないかと。

あとは、導入手順にそって下記のコードを追加すれば OK です。
下記のサンプルコードでは、キャッチされた例外をログに記録することができます。

var crashlytics = FirebaseCrashlytics.initialise();
crashlytics.logException("my caught exception");

なお、Firebase の導入には google-services.jsonGoogleService-Info.plist を設置する必要があります。
こちらについては、下記の Firebase 公式ドキュメントにリンクがありますので、そちらをご参考ください。

Firebase Crashlytics を使ってみる|Firebase
https://firebase.google.com/docs/crashlytics/get-started

また、iOS については Podfile に use_frameworks! を手動で追加する必要があるとのことでしたので、対応ください。
が、それだけでは連携できなかったので、上記の Firebase のドキュメントについても参考にしました。
でもなんか正しくない気がするので、要調整でしょうか。
一度設定をリセットしてからもう一度やり直そうかと思っています。

Android については、エラーは発生しないものの、アプリを実行しても Firebase と連携できず…。
一体何が悪いのか…判明したらまたまとめたいと思います。

 

以上、Cordova アプリに Firebase の Crashlytics を導入する方法でした。
とりあえず、現時点でのまとめなので、進捗あればまたご紹介します。
ご参考になれば幸いです。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】画像をリサイズできるプラグイン「cordova-plugin-image-resizer」

カメラプラグインで取得した画像をリサイズするときに使ったプラグイン「cordova-plugin-image-resizer」のご紹介です。
以前は違う方法でリサイズ処理を行っていたのですが、プラグインを探したらこちらの方が簡単!ということで乗り換えました。

今回使用したプラグインの GitHub はこちらから。

GitHub – JoschkaSchulz/cordova-plugin-image-resizer
https://github.com/JoschkaSchulz/cordova-plugin-image-resizer

 

インストールは下記のコマンドを使います。
が、こちらのプラグインはカメラプラグインの導入が必要とのことでしたので、インストールする前に、先にカメラプラグインをインストールしてください。

// カメラプラグイン
cordova plugin add cordova-plugin-camera
// 画像リサイズプラグイン
cordova plugin add https://github.com/protonet/cordova-plugin-image-resizer.git

あとは、下記のコードを追加すればOKです。
なお、サンプルコードはカメラプラグインで画像を取得するところから記述しています。

// カメラプラグインでアルバムから画像取得
var cameraoptions = {
  sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
  quality: 50,
  encodingType: Camera.EncodingType.JPEG,
  destinationType: Camera.DestinationType.FILE_URI
}
navigator.camera.getPicture(function(imageURI) {
  // 画像リサイズ
  let resizeoptions = {
    uri: imageURI,
    folderName: "[任意のフォルダ名]",
    quality: 70,
    width: 1000,
    height: 1000,
    base64: true,
    fit: false
  };
  window.ImageResizer.resize(resizeoptions,
    function(image) {
       // 画像リサイズ成功時の処理
    }, function() {
      // 画像リサイズ失敗時の処理 
    });
}, function(error) {
  // 画像取得失敗時の処理
}, cameraoptions);

10行目からのリサイズオプションで、画像 URI やリサイズ後の高さや幅、画質などを決定しています。
リサイズ後の画像パスは 20行目のファンクションの引数 image で取得できます。

また、環境の都合上、上記のコードでは リサイズ後の画像は base64 形式になっています。
こちらは 16行目で指定しています。

17行目の fit は、リサイズ後の画像を指定した幅・高さに合わせるかどうかを指定します。
こちらは Android のみに反映される設定です。

 

以上、画像のリサイズを行えるプラグイン「cordova-plugin-image-resizer」のご紹介でした。
ご参考になれば幸いです。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】iframeで指定した外部サイトが表示されないときの対処法【iOS】

Cordova で iframe を使った際に遭遇した不具合についてまとめ。
外部サイトを iframe で表示しようとしたのですが、iOS でだけ表示ができなかったので、その対処法についてです。
なお、Android では問題なく表示できていました。

参考にしたサイトはこちらから。

ionic3 – iframe内に外部サイトが表示できない – memorandum-plus
https://memorandum-plus.com/2018/12/21/ionic3 – iframe内に外部サイトが表示できない(ios不具合)/

なお、外部サイトを開く方法としては、「cordova-plugin-inappbrowser」プラグインを使うという手もあったのですが、レイアウト的な問題で、iframe を使いました。

 

さて、こちらの対処法ですが、config.xml ファイルに下記の一文を追加するだけでした。

<allow-navigation href="*" />

こちらを使うと、WebView 上で使用できる URL を制御することができます。
* を指定すると、全ての URL を許可します。

上記を追加したら、あとは再ビルドして実行してください。
私の環境では、問題なく表示されました。

 

以上、Cordova の iOS アプリで、iframe で指定した外部サイトが表示されないときの対処法でした。
参考になれば幸いです。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】「Refused to load gap://ready because it does not appear in the frame-src directive of the Content Security Policy」エラーの対処法

Cordova で開発中のアプリを iOS で実行したところ、「Refused to load gap://ready because it does not appear in the frame-src directive of the Content Security Policy.」というエラーが発生しました。
Google翻訳にかけてみたところ、「コンテンツセキュリティポリシーの frame-src ディレクティブに表示されないため、gap:// ready の読み込みを拒否しました。」とのことでした。
HTML の Meta タグで指定している Content Security Policy に関する記述のところかとあたりをつけつつ、念のため検索。

こちらの記事がヒットしました。

iOSでRefused to load gap://ready because it appears in neither the child-src directive nor the default-src directive of the Content Security Policy. エラー
https://ufirst.jp/memo/2016/09/16/ios%E3%81%A7refused-to-load-gapready-because-it-appears-in-neither-the-child-src-directive-nor-the-default-src-directive-of-the-content-security-policy-エラー/

 

上記の記事によると、やはり Content Security Policy に関する記述に抜けがあったようで、frame-src の項目に gap://ready file: を追加し、再度実行したところ、今度は問題なくページが表示されました!
なお、記事内には default-src に追加とありましたが、私の環境では、frame-src の項目があったため、こちらに追加しました。
というか、frame-src がある状態で、default-srcgap://ready file: を追加してもこの設定は frame-src には反映されないので、今回のエラーは解決できません。

なので、gap://ready file: の記述は frame-src がある場合は frame-src に、frame-src がない場合は default-src に記述するようにしてください。

 

以上、Cordova アプリを iOS で起動した際に「Refused to load gap://ready because it does not appear in the frame-src directive of the Content Security Policy」エラーが発生するときの対処法でした。

  • この記事いいね! (0)
takahashi 著者:takahashi

風の強さなどをわかりやすく視覚的に表示してくれるWebサービス “Windy.com”

台風などが発生した際、自分の地域やこれから向かう場所がどういう状況なのか、またこれからどうなっていくのか、知りたくなることがあると思います。

最近、風の動きを超感覚的に見ることができるWebサービスを見つけたので、ご紹介したいと思います。

Windy.com

実際にサイトにアクセスしていただければ、白い粒子が地図上を飛び交っているのがわかるかと思います。

この粒子一つ一つの動きが風の流れであり、粒子が進む方向に、粒子の進む速さが早いほど強い風が吹いています。

左下に再生ボタンがありますが、こちらをクリックすると画面下部のプログレスバーが動いていき、現在時刻以降の、風の動きの予測を見ることができます。

内容としては日本で公開されている予測サービスとぱっと見差はないのですが、細かい風の流れを見ることができるため、例えば台風が来た際の自分の住んでいる地域への深刻度がどれぐらいなのかが、他サービスとくらべて実感しやすく、いろいろな判断材料にしやすいのではないかなと思いました。

ちなみにアプリもリリースされているので、スマートフォンからはこちらを利用すると便利そうです。

The app was not found in the store. 🙁

もうこれ以上台風はまったくもって御免ですが、まだもう少し台風シーズンが続きますので、こういったアプリを利用して、防災について考えてみるのもいいかもしれませんね。

  • この記事いいね! (0)