20211125のiOSに関する記事は5件です。

無料でプロトタイプのiOS動画再生アプリを作る話(2021)

概要 iOSアプリ(iPhone等)の開発についていろいろ調べたところ、仲間内の配布であれ、プロトタイプであれ、Appleさん(AppStore)経由でないとまず無理な状況となり、導入障壁となっていると感じております。 開発テストができるTestFlightを使っても、テスト向け配布にはAppleさんの審査が必要だったり、iOSアプリ開発に慣れていなければ開発者プログラムの加入や審査手続き等で時間とお金を持っていかれます。また、サイドローディング等も耳にしますが、真っ当なソフトハウスであれば、ちゃんとお金を払って開発する事になります。 そんな状況の中、iOSで手軽にプロトタイプを配布する事は難しいのか、HelloWorldから一歩踏み込んで模索してみました。 私自身アプリ開発の専門家ではないので、間違いはご指摘いただければ幸いです。 また、私がWEB系開発者である事もあり、基本的にJavaScript(NodeJS)ベースの説明は省略されていますので前提知識がないと難しいかもしれません。 開発・配布手法の比較 ざっと探してみた結果、目についた手法を一覧にまとめました。 手法 制約・問題点 Objective-C, Swift, React Nativeによるパッケージの配布 ・開発者プログラム加入&Apple審査必須・開発者はMac必須・テスタはテスト申請用のAppleID必須 Expoによる配布 ・テスタはExpoアプリ必須・テスタはExpoアカウント必須・プログラムを公開したアカウントと、招待したアカウントでしか動作できない(※iOSの場合)・機能制約多し Snackによる配布 ・テスタはExpoアプリ必須・ソースがオープン(URLを知っている人はソース参照・コピーできてしまう)・機能制約多し・ソースのメンテナンス性悪し(fiddle系なので…) となっています。赤の太文字が障壁となるトピックです。 ざっと見る限り、オープンソースであれば「Snackによる配布」が良さげな感じがします。 いきなり単語が五月雨に出てきたので、軽く説明をします。 Objective-C, Swift とは iOS開発では言わずと知れた基本的な開発言語です。それ単体では他のプラットフォーム(Android)との互換性はありません。 ReactNative とは 上記Objective-C,Swiftを使わず、JavaScript,TypeScript(NodeJS) でiOS/Androidのネイティブアプリが作れるWeb系エンジニアにとっては導入効率の良いフレームワーク。プラットフォームの壁を越えつつ、OS依存する作りこみもできる良いとこ取りの開発手法です。 Expo とは ReactNative をより使いやすくしたSDK ReactNativeよりもできることは少ないですが、Macの開発環境(Xcode)を必要としません。 ReactNativeの機能も一部使えますが、OS依存する機能はExpo側が対応していない限り使えません。 Expoでも他の手法と同様でパッケージとしてビルド可能です。 Snack とは Expo をWEB上でサンドボックス化できるサービス。JSFiddle等をイメージして頂くとわかりやすいです。 例を見ていただいたほうが手っ取り早いかと思い、以下のアプリを公開しました。 JavaScriptやReactを扱える人はこれを見て全てを把握されると思います。 otoge-player 一見・素朴な普通の動画プレイヤーですが、動画プレイヤー自身のタップ操作を無効にすることで、リズムゲーム等のタップ・スワイプ操作練習ができるというある筋では重宝するアプリです。 あくまでお試しだった為、作りが雑で見づらい点もありますが 触って動かせるので、位置や動作を変えてみたり、いろいろ試すことで分かってきます。 なんといっても実機で試せるのはいいですね。 上記Snackは以下のExpoベースの開発を丸ごとSnackに移植したものです。 中身をざっくり説明すると、以下の事をやってます。 iOSの写真にアクセス(許可を取ったり) iOSのカメラロールからビデオを呼び出し再生。ビデオプレイヤー自体に付属する制御を無効化し、外部ボタンから制御 SVG図形表現 CSSによる動的デザイン制御 SVG図形とCSSが使えたら大体のモックアップは作れると思いますが その他使えるか使えないかの判断は本家APIリファレンスをご参照ください Snack (Expo) の導入ポイント ファイル構成と機能 上記Snackを参考にしつつ、説明します。 主に大切なのは以下の2ファイルのみです。 package.json Node.jsのnpmと同様、拡張モジュールを管理 App.js プログラム本体 package.json package.json { "dependencies": { "expo-av": "~10.1.3", "expo-constants": "~12.1.3", "expo-status-bar": "~1.1.0", "react-native-svg": "12.1.1", "expo-image-picker": "~11.0.3", "@expo/vector-icons": "^12.0.0", "react-native-paper": "4.9.2", "expo-screen-orientation": "~4.0.3" } } 見ての通りnpmベースの拡張モジュールが記載されています。 拡張モジュールはpackage.jsonに記載するだけで導入できます。 expo-*** というのがExpo向けの拡張機能 react-native-*** というのがExpoで使えるReactNative向け拡張機能が使えます どんなモジュールがあるのかは上記URLから本家をご参照ください。 導入できるかどうかや、互換性のあるバージョンかどうかは記載した時に示してくれます。 App.js プログラム本体です。名前の通りReactベースですが、JavaScriptが読めて書ければなんとかなるレベルです。 React要素としては、ステート管理をスポットで行っているところぐらいですね。 // 定義 (splashHideというステート変数とsetSplashHideというセッターを定義。この場合、デフォルトはfalse const [splashHide, setSplashHide] = React.useState(false); // 参照 (splashHideの定義は変数の様に参照可能) <View style={[styles.splash,(splashHide)?styles.buttonSvgHide:{}]}> // セッター (セットすると、上記「参照」の値が動的に作用します。setSplashHide関数は非同期であることに注意。セットした直後に変数を参照しても反映されていない) setSplashHide(true); Expoとの互換性 今回 Expoで開発し、それをSnackに移行したのですが、Webのエディタ上に上記2ファイルを普通にコピーアンドペーストで簡単にSnack上に再現できます。 確認した範疇であれば、相違なく動く様です。 Expo/ReactNative以外の拡張モジュールを使えるかは詳細に確認していません。 Snack(Expo)開発のポイント 今回、動画プレイヤーアプリを作ったのですが、開発して分かった事を共有させていただきます。 ・Expoのドキュメントに記載されている事以外は出来ないと考えたほうが良い Expoで提供されている事以外は実現できないケースが多かったので、ドキュメントの記載以外の事はできないと考えたほうがいいです。逆に開発手法選定の基準となると思います。 ・SVG図形はファイルとして扱えない 画像はファイルとして扱えますが、SVGはファイルとして扱えません。react-native-svg という拡張モジュールを導入して、以下の様なSVGファイルをReactNativeのコードに変換するWEBツールを使って変換したものを導入しています。 ・iPhoneのホームバーを隠すことが出来ない iPhoneのホームバー(Home Indicator)を隠すにはApple特有の定義の導入(CocoaPods:pod_install)が必要です。 ReactNativeの場合はnpmの拡張モジュールとしてインストールできるのですが、Expoの場合、Expo自身のSDKが影響してインストールできません。その代わりにExpoSDKで何とかしてもらう形になりますが、ざっと見た感じホームバーの操作については残念ながら対応できていない感じでした。 (今回の動画プレイヤーはそれが重要要素でしたので、縦横画面をひん曲げて無理やり解決しています。) Expoで対応していない機能で「課金機能」等はよく聞くのですが、実際に導入をしていると、ちょっとした機能が対応しておらず、実はそれが意外と重要な要素である事に気づきます。 また、今しれっと重要な事が流されたのですが、Expoは基本的にはReactNativeベースなのですが、Expo自身のSDKが影響してReactNativeの拡張が利用できない場合があります。だからと言ってExpoからReactNativeに移行する場合にはExpoSDKを元に組み上げられたパッケージ構成をReactNative向けにに作り替えないといけません。その為、Expoの実装はあくまでプロトタイプと割り切る必要があります。 ・iPad(iPadOS)の縦横ロックが出来ない Expoにはアプリで画面の縦横を指定して固定する制御ができます。もちろんiPhoneだと出来るのですが、何故か手持ちのiPadでは、それが効きませんでした。 何故かを確認すると、iPadOSにバージョンアップしてから、画面の制御系統が変わって対応できなくなったそうです。こうした、OSのバージョンアップによって以前までは使えていた機能が使えなくなったりする場合があり、その場合の対応はExpoSDK任せとなってしまうところが欠点となります。 まとめ SnackはJSfiddleの様な、スニペット的に「やって見せる」様な用途で使われるものと思いますが、カメラロールへのアクセスやAVコントロール等、結構具体的な事までできるので、プロトタイプの提示として利用するのも良いかもしれません。 参考にさせていただいた記事:
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】toolbar Modifierの表示位置(iOS)

SwiftUIのtoolbarの表示位置です。 全12種で細かい事を言う並びに優先順があるので全部違います。 サンプルコード NavigationView{ Text("Hello, World!") .toolbar{ ToolbarItem(placement: .navigationBarLeading){ Text("leading") } } } } NavigationView内のViewに.toolbar Modifierをつけます。 中にはToolbarItemを使って配置します。 引数placementにToolbarItemPlacementで位置の指定を行います。 対応表 ToolbarItemPlacement(左から順) 表示位置 備考 .navigationBarLeading 左上(leading) .cancellationAction 左上(leading) .navigation 左上(leading) .principal 中央(center) .automatic 右上(trailing) .navigationBarTrailing 右上(trailing) .primaryAction 右上(trailing) .destructiveAction 右上(trailing) confirmationActionと同じ優先順位 .confirmationAction 右上(trailing) destructiveActionと同じ優先順位太文字(bold) .bottomBar 下部(bottom) デフォルトは中央statusがあると左端 .status 下部(bottom) .keyboard キーボード 実際に使うものは? 以下の4つが主になると思います。 .navigationBarLeading .navigationBarTrailing .bottomBar .keyboard 中身はHStackで配置できるので、無理に色々使わずにHStackで並べた方が無難です。 無理に複数使って並べて順序がおかしくなることのないようにしましょう。 余談 iOSバージョンについて toolbarはiOS14から使用出来ます。 navigationBarItemが非推奨になったので、問題が無ければ随時置き換えを行いましょう。 .keyboardはiOS15からです。 iOS14では使用出来ないので注意して下さい。 ブログ記事の紹介 ツールバーについて更に説明が見たい方はこちら ToolbarItem無しで簡易的な使い方をする場合や、 複数並べた場合のサンプルコード、 キーボードについての補足などがあります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】画面の戻り方のまとめ

Swiftで画面を戻る処理が何種類かあるのでまとめてみました。 モーダル型で戻る self.dismiss(animated: true, completion: nil) dismissで画面を破棄しています。 モーダル型で2つ前の画面に戻る self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) 2つ前の画面に戻るコードです。 1つ前の画面へ戻る(NavigationController) self.navigationController?.popViewController(animated: true) NavigationControllerで1つ前の画面へ戻る処理。 トップの階層へ戻る(NavigationController) self.navigationController?.popToRootViewController(animated: true) NavigationControllerでトップの階層へ戻る処理。 任意の階層へ戻る(NavigationController) self.navigationController?.popToViewController(navigationController!.viewControllers[階層の番号], animated: true) NavigationControllerで任意の階層へ戻る処理。 *戻るだけで先に進むことはできません。 参考 https://naoya-ono.com/swift/navigation-controller-back/ https://qiita.com/Walkdream24/items/787df7d5b6e85330416a
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Flutter] FCM vs Local Notification

はじめに FlutterでAndroidとiOSのアプリを両方開発しているところで、Push Notificationを実装することになりました。 最初はFCMとLocal Notificationの機能に関して紛らわしいことがありましたので、今回はこれに関して整理しようと思います。 FCM (Firebase Cloud Messaging) Firebase Cloud Messaging(FCM)は、メッセージを無料で確実に送信するためのクロスプラットフォーム メッセージング ソリューションです。 Firebaseサイトで定義されてる概念で、Firebaseサーバーを使って簡単にユーザーにメッセージを送信することができるとで理解すれば、大丈夫だと思います。 FlutterにFCMを適用する方法 Flutterでは、firebase_messagingのパッケージを追加して使用することができます。 注意することはiOSはAPNsキーもしくはAPNs認証書を登録を事前にしなければ、送信できないので、面倒だけどXcodeの方でAPNsの登録を含めてbundle ID設定やProvisioning Profile設定をしましょう。 あと、他のFirebaseパッケージ、例えば、firebase_authやfirebase_coreなどを使うことになったら、バージョンの互換性も考えないとビルドエラーが起こる可能性もあるので気をつけた方がいいです。 FlutterのLocal Notification A cross platform plugin for displaying and scheduling local notifications for Flutter applications with the ability to customise for each platform. これもFCMみたいにメッセージを送信するためのクロスプラットフォームです。 FlutterにLocal Notificationを適用する方法 Local Notificationもfirebase_messagingようにflutter_local_notificationsのパッケージを追加すれば使用することができます。 FCMとLocal Notificationの共通点 両方Android,iOSにメッセージを無料で送信することができる メッセージの予約可能 Notification許可ダイアログを出すことができる (これ以上何かあったら、Feedbackしてください?) FCMとLocal Notificationの相違点 FCMはiOSの方の追加的な対応が必要(bundle ID, Provisioning Profile, APNsキー, tokenなど) FCMはメッセージの中に画像を表示したいなら、Flutter上にObjective-Cで対応しなければならない。 FCMはfirebaseをデータベースとして使用している場合は、クラウド機能を使用してデータベースに加えられた変更をlistenすることができる。 用語の違い:機能がほぼ同じでFCMとLocal Notificationを話すとき、プッシュ通知もしくはPush Notificationと言われるですが、これは正しくないです。 Local Notificationはデバイス上にローカルにアプリ自体から送信、予約されたNotificationです。 Push NotificationはiOSやAndroidのクラウドシステム(APNs,FCMなど)を通じてアプリに送信されたNotificationです。 まとめ つまり、用語的にFCMはPush Notification, ローカルで送信する通知はLocal Notificationです。FCMはユーザーのデータベースをもとにAPNsとトークンを通してメッセージを送信、Local Notificationはこれに関係なくてメッセージを送信することができます。もちろん、Push Notificationの方がLocal Notificationより細かい設定や実装が必要です。実装したいことによって、ちゃんと検討して実装した方がいいと思いますね。 参考 いつもFeedback歓迎 Feedbackはコメントでお願いします。 では、Happy coding!??
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Freezedの使い方

はじめにFreezedとは 簡単に言えばコピーメソッド等を含むImmutable(不変)なクラスを生成することができるパッケージのこと Freezedでコードを生成することで便利なメソッドがいくつか使用できるようになる。 ・copyWith nullを割り当てることが可能な複製メソッド ・== 同値であることの確認 ・toString 文字列化した時の結果 ・fromJson Mapからの変換 ・toJson Mapへの変換 上記のメソッドを使用して開発を楽にしましょう! Freezedの使用方法 インストール pubspec.yaml dependencies: // @freezed などを使うために必須 freezed_annotation: dev_dependencies: //コード生成するために必要 build_runner: freezed: // fromJson/toJson を生成させたい場合に必要になる json_serializable: Freezedクラスの書き方 例として、友人の情報をまとめたFriendクラスをfriend.dartファイルを作成して、 そこに定義していく。 friend.dart import 'package:freezed_annotation/freezed_annotation.dart'; // {ファイル名}.freezed.dart と書く part 'friend.freezed.dart'; //Freezed特有の書き方なので、スニペットを用意するのが良い @freezed class Friend with _$Friend { const factory Friend({ /// 友人の名前 required String name, //requiredで必須項目にする }) = _Friend; } 上記のコードのようにプロパティを必須項目にするには定義するプロパティの前にrequiredを記述する。 他にもnull許容にする場合、デフォルト値を設定する場合には下記のようにする。 null許容 String? name デフォルト値 @Default('qiita君') String name Freezedなクラスの定義が完了したら次にターミナルで下記のコマンドを入力し Build Runnerの機能を使用し、コードを生成する。 ターミナル flutter pub run build_runner build Freezedクラスの修正や変更があった時などに、変更ごとに上記のコードを入力するのが面倒だと思います、そのためにファイルの更新を検知して自動で再生成してくれるコマンドも用意されています。 簡単です。上記のコードの最後のbuildをwatchに変えるだけ! ターミナル flutter pub run build_runner watch コードを生成してからそれだけで終了せず、監視を行ってくれます。 Freezedクラスを編集してコード生成をすると、古い生成済みファイルと競合しエラーが発生することがあります。 delete-conflicting-outputs オプションを付けることで、競合ファイルを削除して再生成してくれます。 ターミナル flutter pub run build_runner watch --delete-conflicting-outputs Jsonから変換 または Jsonへの変換 をするために(fromJson/toJson) Jsonから変換 Jsonへ変換するためのメソッドを生成するためには Freezedだけではできないので 最初にpubspec.yamlに記入した json_serializable を使用し生成する。 JSON相互変換メソッドを生成させるには以下の2行を追加します。 part 'friend.g.dart' を追加 fromJson用のfactoryコンストラクタを追加 friend.dart import 'package:freezed_annotation/freezed_annotation.dart'; part 'friend.freezed.dart'; part 'friend.g.dart'; // 追加 @freezed class Friend with _$Friend { const factory Friend({ required String name, }) = _Friend; // {} ではなく =>(アロー)を使ってください factory Friend.fromJson(Map<String, dynamic> json) => _$FriendFromJson(json); } これで、 fromJson, toJson 両方のメソッドが生成されるようになりました! リントツールでのエラーが出る場合の対処方法 使用しているリントツールによっては、「コードがおかしいですよ」と怒られることもあるので、その場合は下記のように、 analysis_options.yaml で生成ファイルを対象外にしましょう。 analysis_options.yaml analyzer: exclude: - "**/*.freezed.dart" - "**/*.g.dart" 今回参考にさせて頂いた記事 主にRiverpodの使い方など本当にわかりやすく書かれています、 今回の記事は以下の記事のほんの一部に過ぎないので、 ぜひ参考にしてみて下さい!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む