20190506のiOSに関する記事は9件です。

iOS / macOS どちらでも使用できる UIKit/AppKit クラスの定義を考える

はじめに

iOS の UIKit と macOS の AppKit はクラス名が前者は UI プレフィックス、後者が NS プレフィックスである。
例えば、UIColor / NSColor, UIButton / NSButton などがある。

iOS / macOS どちらでも動作するコードを書く際、いちいちコード内でプラットフォームごとにクラス名を切り分けすることは面倒なので、この違いを吸収できるような定義の方法を考える。

定義例

以下のような定義を入れておくと、 CrossPlatformXXX でプラットフォームを意識せずにクラス名を書ける。

CrossPlatform.swift
#if os(iOS)
import UIKit

public typealias CrossPlatformRect = CGRect
public typealias CrossPlatformColor = UIColor
public typealias CrossPlatformViewController = UIViewController
#elseif os(macOS)
import AppKit

public typealias CrossPlatformRect = NSRect
public typealias CrossPlatformColor = NSColor
public typealias CrossPlatformViewController = NSViewController
#endif

UIKit / AppKit のクラスで共通のインターフェースを使う分にはこれで OK なのだが、クラスのインターフェースが違う部分を含めて同一クラスのように扱いたい場合は、インターフェースをどちらかにすり合わせると良い。

例えば、 UIButton(UIControl) には addTarget メソッドが存在するが、 NSButton(NSControl) には addTarget メソッドは存在しない。

この場合、NSButton のインターフェースを UIButton に寄せて同一のように扱うためには、以下のようにする。

CrossPlatformButton.swift
#if os(iOS)
import UIKit

open class CrossPlatformButton: UIButton {
  open func addTarget(_ target: Any?, action: Selector) {
    addTarget(target, action: action, for: .touchUpInside)
  }
}

#elseif os(macOS)
import AppKit

open class CrossPlatformButton: NSButton {
  open func addTarget(_ target: Any?, action: Selector) {
    self.target = target as AnyObject?
    self.action = action
  }
}

#endif

これで CrossPlatformButton の addTarget メソッドを使用することで、ターゲットとアクションの設定を、プラットフォームの差を意識せず実施できるようになる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

KotlinMPPでAndroid/iOS両対応のHTTPクライアントライブラリを作る

はじめに 

 Android/iOS、両プラットフォーム上で同じようなアプリを開発する際、明らかに同じような処理をKotlin/Swiftで実装することがあり、共通化したいなと思うところがありました。
例えば、通信部分やEntity、ValueObjectなど、OSが違っても共通になる処理については尚更です。こういった部分を二度も違う言語で実装するのは明らかに二度手間で余計な工数がかかりますし、バグが発生する可能性も増します。
なんとかこういった部分を共通化し、一度コードを書けば両デバイスで動かせる、それによって工数の削減をしたい。そういったモチベーションがあったため、KotlinMPPについて調査を行い、実際にそれを用いて両プラットフォームに一度で対応できるHTTPクライアントを作ってみました。

KotlinMPPとは

正式名称 Kotlin Multiplatform Project
Kotlin1.2及び1.3で実験的に提供されている機能です。Gradleでターゲットとなるプラットフォームにどんな方法でビルドをするかを記述することで、一つのKotlinのソースを各プラットフォーム向けに動作する形でビルドすることが出来ます。
例えば、AndroidではJVMで動作するようにビルドする、iOSではネイティブで動作するようにビルドする、といった次第です。
Anrdoid,iOSはもちろん、mac,Windows,JSをターゲットとすることが出来ます。

KotlinMPPを使ったHTTPクライアントライブラリ

サンプルプロジェクトを作ってみました。
5hyn3/KotlinMPPHttpClientSample

以下のような言語やビルドツール、ライブラリを組み合わせて作られています

  • kotlin

    • 1.3.31
  • gradle

    • 5.4.1
  • ktor-client

    • 1.1.5
  • kotlinx.serialization

    • 0.11.0
  • kotlinx.coroutin

    • 1.2.1

テストが一つ記述されており、実際にAPIからjsonを取得し、パースしてkotlinのオブジェクトとして取得する部分までの動作を確認することが出来ます。実際にアプリに組み込んで動作を確認したい場合は以下を参考にしてください。

Multiplatform Project: iOS and Android

ビルド成果物としてjarとframeworkができるので、それらを扱う形になります。

現状、AndroidとiOSのみをターゲットに作っていますが、gradleに手を入れることでJSなどにも対応させることが出来ます。

苦労した点

以下サンプルプロジェクトを作った際に遭遇した大変だった点を書いていきます

バージョンごとにビルド時の挙動が違っており適切なバージョンの組み合わせを見つけるのが大変だった

主にGradleによるものです。色々なプロジェクトを参考にしてサンプルプロジェクトを作りましたが、バージョンがちょっとでも違うと全くビルドすら出来ませんでした。また、ライブラリが要求するGradleのバージョンが食い違っていたりして悩んだこともありました。
最終的に、現時点での最新版である5.4.1を採用することで解決しました。本プロジェクト作成に費やした時間の8割くらいはここで適切なライブラリを選定することで消費されています。まだexperimentalなのでこのあたりはどうしてもしょうがないですね。

suspendなmethodをSwiftから呼び出せない

現状Kotlin/Nativeはsuspendなmethodをswiftから呼び出せるインターフェースを作ってくれないようです。suspendをやめ、Defferdインスタンスを返すようにすることでSwiftからもきちんと扱えるようになりました。こちらであればSwift側からも扱えるインターフェースが提供されており、問題なく呼び出すことが出来ます。

Kotlin/Nativeでビルドした際にランタイムでIncorrectDereferenceExceptionが発生する

 本プロジェクトでは非プリミティブ型のトップレベル変数をメインスレッド外から触ろうとしたために発生しました。具体的にどこで発生したかというと、ここです。対処法としては@ThreadLocalを付与して、スレッドローカルとして扱うことで対応を行いました。

終わりに

 これでKotlinでコードを一つ書けばAndroid/iOS両方で動くライブラリを作ることが出来ました。これでより業務を加速し、同じことを二回も書くようなつまらない作業は減らして、もっと本質の部分に時間を使うことが出来るようになるといいなぁと思います。

参考

JetBrains/kotlin-mpp-example
Multiplatform Project: iOS and Android
kotlin-native /IMMUTABILITY.md
DroidKaigi/conference-app-2019
SimonSchubert/Newsout

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エンジニアとデザイナー向けのSNSアプリを作りました!【会員登録が100人突破しました!大感謝】

ende_1.jpg
気づいたら10連休最終日!!
会社員になって中々まとまった休みが無い中、やってきたゴールデン10連休!!!

ここぞとばかり徹夜でアプリ作成に挑戦し、つい先日Appleの審査が通り本日リリースを迎えることが出来ました!!
何とも言えない達成感です。

その紹介も兼ねて、どういった技術を使用してこのアプリを作ったのかを簡単にまとめましたので読んでいただけると嬉しくて飛び跳ねます。

EndeLinkとは

Apple Storeの紹介にも記載してますが、このアプリはデザイナーとエンジニアに特化したお仕事探しアプリです。登録されたエンジニアまたはデザイナーの作品、金額、頻度で適切な仕事パートナーを探し出すことができます。
つまり、読んで字のごとくエンジニアとデザイナーを探すのにフォーカスしたSNSアプリです。

作った背景

昔、フリーランスを少しかじっていた時期があるのですが、知人のエンジニアやデザイナーさんに頼みたいけど金額面で気を使わせたり、可動日数が合わず調整が難しかったり…苦労しました…。
その頃からエンジニアやデザイナーさんを探すことに注力した良い感じのSNSをいつか作りたいなと思っていました。
現在はフリーではなく会社員ですが、会社が副業OKなので自分も仕事相手を探す機会も出てくるだろうと思い、思い切ってこの10連休を活かして開発しようと思いました。

EndeLinkはどのようにして作られたのか

ende_board.png

デザイン

スクリーンショット 2019-05-05 9.27.34.png
色々コーディングをやってきましたが、デザインを作ったことは一度もなくセンスもないと認識しているためにAdobe XDでちゃちゃっとワイヤーフレームを作りました。
(軌道に乗れば、デザイナーさんにちゃんと制作を依頼したいです)
一番注意して作ったのが、このアプリの使用目的を明確にすることです。
そこでこのアプリは仕事パートナーを見つけるのに大事になってくる、お金や可動日数の入力を必須にし、そこをソート出来るようにしました。
またポートフォリオのURLやポートフォリオ画像も数点貼れるようにしときました。

あと、スペースはなるべく統一して作りました。
例えば上記リストページはiPhoneのファーストビューで自己紹介をMax数書いても2つのリストは最低でも見せれるように空きを調整しました。
空きをきちんと取ることにより、見た目が綺麗に見える?感じがします。
あとは実際に作りながらかなり調整していきました。

開発するプラットフォーム選び

スクリーンショット 2019-05-05 8.35.35.png
フロントエンドの技術だけでアプリが開発できるプラットフォームとして国内で開発している会社として有名な Monaca を選びました。
フロントエンドだけのアプリ開発も徐々に選択できるようになりましたが、自分はこのMonacaのプラットフォームを利用して良かったと思うところは、日本語のドキュメントが充実している所です。
国内で開発している会社なので当たり前かもしれませんが、日頃英語のドキュメント見るのが当たり前なので、日本語のドキュメントが充実しているのは何より新鮮でしたし、大変助かりました。
あと国内産ってなぜか安心するんですよね、まー食べませんが( º﹃º` )…… はい。

ちなみに当たり前ですが、お問い合わせも日本語で出来るのでこれも非常に助かります。
ただしお問い合わせがテクニカルだと、お金をがっつり取られる場合があるのでそこは注意していただきたいです。

興味がある方は、下記料金プランを見ていただけると大体いくら掛かるのかが分かります。
https://ja.monaca.io/pricing.html

使用したバックエンドサービス

スクリーンショット 2019-05-05 8.51.51.png
Qiitaでもかなりの頻度で取り上げられる Firebase を使用しました。
Firebaseで利用したプロダクトは下記4つで、
- データベースの用意として「Realtime Database
- 画像などのデータアップ先として「Cloud Storage
- その次がSNS認証として「Authentication
- あと一部アプリからデータを送信する技術を使用しているため「Cloud Functions
以上のプロダクトを用いて開発しました。
見て分かるように、Firebase一つで多種多様なプロダクトを使用できるので大変助かります。
話が少しそれるのですがFirebaseの中で色々なプロダクトが年々増えてきているのですが、最近気になるのが Google の機械学習技術を用いた「ML Kit
まだベータなのですが、このAPIを利用することによテキスト認識(OCR)はもちろん顔認識を利用した技術も使用することが出来ます。
Firebaseの母体はGoogleなので、Googleで開発された技術がFirebaseでも使用できるのも嬉しいですね。

・データベースのセキュリティについて
Firebase Realtime Databaseではセキュリティ設定を細かく設定することができますが、、、ここで唐突に問題です!
管理権限を持たない一般ユーザは下記 grandchild のルートには読み取りアクセスできますでしょうか?

{  
   "rules":{  
      ".read":false,
      "parent":{  
         "child":{  
            ".read":true,
            "grandchild":{  
               ".read":false
            }
         }
      }
   }
}





正解は「出来ます」
なぜならその親の child ルートで読み取りを許可したので、その権限が子に引き継かれるからです。
なので読み取り先である grandchild の読み取りを不可にしても、親のアクセス権限が適用されます。

ということは仮にトップルートで読み取りがアクセス許可されていた場合は、いくら子が読み取りアクセス不可にしても全体にアクセスできてしまうことになります。

{  
   "rules":{  
      ".read":true,
      "parent":{  
        "child":{  
        //アクセス出来てしまう 
        ".read":false,
            "grandchild":{  
              //アクセス出来てしまう 
              ".read":false
            }
         }
      }
   }
}

まーこんなことしないでしょうが。。

このようにアクセス権限は親ルートにアクセス権限をもたせた場合、それは子に影響されます。
なので今回作ったアプリではアクセス出来るルート権限ごとに細かく分けてルールを定義し、権限通りに動いてるかチェック表をつけました。
スクリーンショット 2019-05-05 11.19.30.png
ご存知の方も多いと思いますが、Firebaseではデータのアクセス権限の確認をコンソールからシミュレートすることが出来ます。
スクリーンショット 2019-05-05 16.36.38.png

より詳しく知りたい方は、下記ドキュメントを見てください。
https://firebase.google.com/docs/database/security/securing-data?hl=ja#read_and_write_rules_cascade


・メール認証について
今回ログイン認証としてパスワード認証メール認証を組み合わせてログインできるようにしてます。
メール認証はログイン後に下記方法で送ることが出来ます。

firebase.auth().currentUser.sendEmailVerification().then(function() { 
  //success
}).catch(function(error) { 
  window.alert(error); 
}); 

送られてきたメールのパラメータには mode や oobCode、apiKeyが付属してます。
メール認証の場合は mode は 'verifyEmail'になります。
他にもパスワード変更やメールアドレス変更などの際の mode があります。
参照 : https://firebase.google.com/docs/auth/custom-email-handler#create_the_email_action_handler_page

例えばメール認証の一例として

auth.checkActionCode(actionCode).then(function() { 
  //ワンタイムコード(oobCode)の確認
  auth.applyActionCode(actionCode).then(function() { 
    //メールアドレス認証を確認
  }).catch(function(error) { 
      window.alert(error); 
  }); 
}).catch(function(error) {  
  window.alert(error);
}); 

checkActionCodeでワンタイムコードを確認し有効であれば、applyActionCodeにてメールアドレス認証を確認することができます。

実際にメール認証されたかどうかは、Firebaseのログイン認証から一度ログアウトする必要があります。
メール認証の確認は firebase.auth().currentUser.emailVerified を使用します。

firebase.auth().signOut().then(function(){ 
  firebase.auth().signInWithEmailAndPassword(email, pass).then(function (info) { 
    if(firebase.auth().currentUser.emailVerified) { 
      //メールアドレス認証済み 
    } else { 
      //メールアドレス認証エラー 
    } 
  }).catch(function (error) { 
    window.alert(error); 
  }); 
}); 


使用したJSフレームワーク

スクリーンショット 2019-05-05 9.20.04.png
おなじみの Vue.js、今回SPAで開発しているためにVue.jsでコーディングさせていただきました。
またSPAを構築する際に Vue Router を使用するかと思いますが、自分は知らなかったので共有として下記方法で一つのコンポーネントに対して複数のパス(alias)を関連付けることもできます。

const Vue = require('vue');
const VueRouter = require('vue-router');
const Main = require('./Main');

Vue.use(VueRouter);

const routes = [{
  path: '/main',
  component: Main,
  alias: ['/page1', '/page2', '/page3']
}];

基本的に path と component は対になってますが、例えば alias に設定した /page1 にアクセスした際に component の Main を共有して使うことが出来ます。
ユーザーから見ると /main と /page1 は別々のURLの為に当然別のページを見てると思うのですが、裏側では共通のページを見ていることになります。

Appleからの審査について

スクリーンショット 2019-05-05 13.48.09.jpg
今回アプリの審査で2回リジェクトを食らったのですが、作ったのがSNSアプリということもあり下記基準に満たしていませんでした。
スクリーンショット 2019-05-05 13.56.02.png
これは書いてあるように、ユーザーがユーザーに対して不適切な行為をされた場合、それを防ぐ/報告手段を実装しなければならいということでした。
そこでユーザーのブロック機能と報告機能を実装して報告したところ、無事通りました。
rb.jpg

最後に

このEndeLinkはApple Storeに公開されようやくスタートしたばかりなので、機能拡張やデザイン改修も含めてこれからやりたいことだらけです。

あともし可能であればぜひ知り合いのデザイナーさんやエンジニアさんに紹介してもらえると有り難いです( ´^`° )

以上、読んで頂きありがとうございました。
また「いいね」を押していただけると大変励みになります(っ_ _)っ


スクリーンショット 2019-05-06 11.25.20.png

※Firebaseの料金プランの兼ね合いから、会員数によって会員登録に制限をかける可能性があります。
※今の所、このアプリは全て無料でご利用できます(広告無)

バグ報告/ご意見は、Twitterからダイレクトメッセージにてご連絡ください!
※些細なことでも言っていただけると嬉しいです(´∩ω∩`)
※唯の批判などはスルーします、人としても。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エンジニアとデザイナー向けのSNSアプリを作りました!【会員登録が100人突破しました!感謝】

ende_1.jpg
気づいたら10連休最終日!!
会社員になって中々まとまった休みが無い中、やってきたゴールデン10連休!!!

ここぞとばかり徹夜でアプリ作成に挑戦し、つい先日Appleの審査が通り本日リリースを迎えることが出来ました!!
何とも言えない達成感です。

その紹介も兼ねて、どういった技術を使用してこのアプリを作ったのかを簡単にまとめましたので読んでいただけると嬉しくて飛び跳ねます。

EndeLinkとは

Apple Storeの紹介にも記載してますが、このアプリはデザイナーとエンジニアに特化したお仕事探しアプリです。登録されたエンジニアまたはデザイナーの作品、金額、頻度で適切な仕事パートナーを探し出すことができます。
つまり、読んで字のごとくエンジニアとデザイナーを探すのにフォーカスしたSNSアプリです。

作った背景

昔、フリーランスを少しかじっていた時期があるのですが、知人のエンジニアやデザイナーさんに頼みたいけど金額面で気を使わせたり、可動日数が合わず調整が難しかったり…苦労しました…。
その頃からエンジニアやデザイナーさんを探すことに注力した良い感じのSNSをいつか作りたいなと思っていました。
現在はフリーではなく会社員ですが、会社が副業OKなので自分も仕事相手を探す機会も出てくるだろうと思い、思い切ってこの10連休を活かして開発しようと思いました。

EndeLinkはどのようにして作られたのか

ende_board.png

デザイン

スクリーンショット 2019-05-05 9.27.34.png
色々コーディングをやってきましたが、デザインを作ったことは一度もなくセンスもないと認識しているためにAdobe XDでちゃちゃっとワイヤーフレームを作りました。
(軌道に乗れば、デザイナーさんにちゃんと制作を依頼したいです)
一番注意して作ったのが、このアプリの使用目的を明確にすることです。
そこでこのアプリは仕事パートナーを見つけるのに大事になってくる、お金や可動日数の入力を必須にし、そこをソート出来るようにしました。
またポートフォリオのURLやポートフォリオ画像も数点貼れるようにしときました。

あと、スペースはなるべく統一して作りました。
例えば上記リストページはiPhoneのファーストビューで自己紹介をMax数書いても2つのリストは最低でも見せれるように空きを調整しました。
空きをきちんと取ることにより、見た目が綺麗に見える?感じがします。
あとは実際に作りながらかなり調整していきました。

開発するプラットフォーム選び

スクリーンショット 2019-05-05 8.35.35.png
フロントエンドの技術だけでアプリが開発できるプラットフォームとして国内で開発している会社として有名な Monaca を選びました。
フロントエンドだけのアプリ開発も徐々に選択できるようになりましたが、自分はこのMonacaのプラットフォームを利用して良かったと思うところは、日本語のドキュメントが充実している所です。
国内で開発している会社なので当たり前かもしれませんが、日頃英語のドキュメント見るのが当たり前なので、日本語のドキュメントが充実しているのは何より新鮮でしたし、大変助かりました。
あと国内産ってなぜか安心するんですよね、まー食べませんが( º﹃º` )…… はい。

ちなみに当たり前ですが、お問い合わせも日本語で出来るのでこれも非常に助かります。
ただしお問い合わせがテクニカルだと、お金をがっつり取られる場合があるのでそこは注意していただきたいです。

興味がある方は、下記料金プランを見ていただけると大体いくら掛かるのかが分かります。
https://ja.monaca.io/pricing.html

使用したバックエンドサービス

スクリーンショット 2019-05-05 8.51.51.png
Qiitaでもかなりの頻度で取り上げられる Firebase を使用しました。
Firebaseで利用したプロダクトは下記4つで、
- データベースの用意として「Realtime Database
- 画像などのデータアップ先として「Cloud Storage
- その次がSNS認証として「Authentication
- あと一部アプリからデータを送信する技術を使用しているため「Cloud Functions
以上のプロダクトを用いて開発しました。
見て分かるように、Firebase一つで多種多様なプロダクトを使用できるので大変助かります。
話が少しそれるのですがFirebaseの中で色々なプロダクトが年々増えてきているのですが、最近気になるのが Google の機械学習技術を用いた「ML Kit
まだベータなのですが、このAPIを利用することによテキスト認識(OCR)はもちろん顔認識を利用した技術も使用することが出来ます。
Firebaseの母体はGoogleなので、Googleで開発された技術がFirebaseでも使用できるのも嬉しいですね。

・データベースのセキュリティについて
Firebase Realtime Databaseではセキュリティ設定を細かく設定することができますが、、、ここで唐突に問題です!
管理権限を持たない一般ユーザは下記 grandchild のルートには読み取りアクセスできますでしょうか?

{  
   "rules":{  
      ".read":false,
      "parent":{  
         "child":{  
            ".read":true,
            "grandchild":{  
               ".read":false
            }
         }
      }
   }
}





正解は「出来ます」
なぜならその親の child ルートで読み取りを許可したので、その権限が子に引き継かれるからです。
なので読み取り先である grandchild の読み取りを不可にしても、親のアクセス権限が適用されます。

ということは仮にトップルートで読み取りがアクセス許可されていた場合は、いくら子が読み取りアクセス不可にしても全体にアクセスできてしまうことになります。

{  
   "rules":{  
      ".read":true,
      "parent":{  
        "child":{  
        //アクセス出来てしまう 
        ".read":false,
            "grandchild":{  
              //アクセス出来てしまう 
              ".read":false
            }
         }
      }
   }
}

まーこんなことしないでしょうが。。

このようにアクセス権限は親ルートにアクセス権限をもたせた場合、それは子に影響されます。
なので今回作ったアプリではアクセス出来るルート権限ごとに細かく分けてルールを定義し、権限通りに動いてるかチェック表をつけました。
スクリーンショット 2019-05-05 11.19.30.png
ご存知の方も多いと思いますが、Firebaseではデータのアクセス権限の確認をコンソールからシミュレートすることが出来ます。
スクリーンショット 2019-05-05 16.36.38.png

より詳しく知りたい方は、下記ドキュメントを見てください。
https://firebase.google.com/docs/database/security/securing-data?hl=ja#read_and_write_rules_cascade


・メール認証について
今回ログイン認証としてパスワード認証メール認証を組み合わせてログインできるようにしてます。
メール認証はログイン後に下記方法で送ることが出来ます。

firebase.auth().currentUser.sendEmailVerification().then(function() { 
  //success
}).catch(function(error) { 
  window.alert(error); 
}); 

送られてきたメールのパラメータには mode や oobCode、apiKeyが付属してます。
メール認証の場合は mode は 'verifyEmail'になります。
他にもパスワード変更やメールアドレス変更などの際の mode があります。
参照 : https://firebase.google.com/docs/auth/custom-email-handler#create_the_email_action_handler_page

例えばメール認証の一例として

auth.checkActionCode(actionCode).then(function() { 
  //ワンタイムコード(oobCode)の確認
  auth.applyActionCode(actionCode).then(function() { 
    //メールアドレス認証を確認
  }).catch(function(error) { 
      window.alert(error); 
  }); 
}).catch(function(error) {  
  window.alert(error);
}); 

checkActionCodeでワンタイムコードを確認し有効であれば、applyActionCodeにてメールアドレス認証を確認することができます。

実際にメール認証されたかどうかは、Firebaseのログイン認証から一度ログアウトする必要があります。
メール認証の確認は firebase.auth().currentUser.emailVerified を使用します。

firebase.auth().signOut().then(function(){ 
  firebase.auth().signInWithEmailAndPassword(email, pass).then(function (info) { 
    if(firebase.auth().currentUser.emailVerified) { 
      //メールアドレス認証済み 
    } else { 
      //メールアドレス認証エラー 
    } 
  }).catch(function (error) { 
    window.alert(error); 
  }); 
}); 


使用したJSフレームワーク

スクリーンショット 2019-05-05 9.20.04.png
おなじみの Vue.js、今回SPAで開発しているためにVue.jsでコーディングさせていただきました。
またSPAを構築する際に Vue Router を使用するかと思いますが、自分は知らなかったので共有として下記方法で一つのコンポーネントに対して複数のパス(alias)を関連付けることもできます。

const Vue = require('vue');
const VueRouter = require('vue-router');
const Main = require('./Main');

Vue.use(VueRouter);

const routes = [{
  path: '/main',
  component: Main,
  alias: ['/page1', '/page2', '/page3']
}];

基本的に path と component は対になってますが、例えば alias に設定した /page1 にアクセスした際に component の Main を共有して使うことが出来ます。
ユーザーから見ると /main と /page1 は別々のURLの為に当然別のページを見てると思うのですが、裏側では共通のページを見ていることになります。

Appleからの審査について

スクリーンショット 2019-05-05 13.48.09.jpg
今回アプリの審査で2回リジェクトを食らったのですが、作ったのがSNSアプリということもあり下記基準に満たしていませんでした。
スクリーンショット 2019-05-05 13.56.02.png
これは書いてあるように、ユーザーがユーザーに対して不適切な行為をされた場合、それを防ぐ/報告手段を実装しなければならいということでした。
そこでユーザーのブロック機能と報告機能を実装して報告したところ、無事通りました。
rb.jpg

最後に

このEndeLinkはApple Storeに公開されようやくスタートしたばかりなので、機能拡張やデザイン改修も含めてこれからやりたいことだらけです。

あともし可能であればぜひ知り合いのデザイナーさんやエンジニアさんに紹介してもらえると有り難いです( ´^`° )

以上、読んで頂きありがとうございました。
また「いいね」を押していただけると大変励みになります(っ_ _)っ


スクリーンショット 2019-05-06 11.25.20.png

※Firebaseの料金プランの兼ね合いから、会員数によって会員登録に制限をかける可能性があります。
※今の所、このアプリは全て無料でご利用できます(広告無)

バグ報告/ご意見は、Twitterからダイレクトメッセージにてご連絡ください!
※些細なことでも言っていただけると嬉しいです(´∩ω∩`)
※唯の批判などはスルーします、人としても。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あなたのお役に立てるかもしれないアプリを、フロントエンド開発でついにリリースを迎えることが出来ました!

ende_1.jpg

気づいたら10連休最終日!!
会社員になって中々まとまった休みが無い中、やってきたゴールデン10連休!!!

ここぞとばかり徹夜でアプリ作成に挑戦し、つい先日Appleの審査が通り本日リリースを迎えることが出来ました!!
何とも言えない達成感です。

その紹介も兼ねて、どういった技術を使用してこのアプリを作ったのかを簡単にまとめましたので読んでいただけると嬉しくて飛び跳ねます。

EndeLinkとは

Apple Storeの紹介にも記載してますが、このアプリはデザイナーとエンジニアに特化したお仕事探しアプリです。登録されたエンジニアまたはデザイナーの作品、金額、頻度で適切な仕事パートナーを探し出すことができます。
つまり、読んで字のごとくエンジニアとデザイナーを探すのにフォーカスしたSNSアプリです。

作った背景

昔、フリーランスを少しかじっていた時期があるのですが、知人のエンジニアやデザイナーさんに頼みたいけど金額面で気を使わせたり、可動日数が合わず調整が難しかったり…苦労しました…。
その頃からエンジニアやデザイナーさんを探すことに注力した良い感じのSNSをいつか作りたいなと思っていました。
現在はフリーではなく会社員ですが、会社が副業OKなので自分も仕事相手を探す機会も出てくるだろうと思い、思い切ってこの10連休を活かして開発しようと思いました。

EndeLinkはどのようにして作られたのか

ende_board.png

デザイン

スクリーンショット 2019-05-05 9.27.34.png
色々コーディングをやってきましたが、デザインを作ったことは一度もなくセンスもないと認識しているためにAdobe XDでちゃちゃっとワイヤーフレームを作りました。
(軌道に乗れば、デザイナーさんにちゃんと制作を依頼したいです)
一番注意して作ったのが、このアプリの使用目的を明確にすることです。
そこでこのアプリは仕事パートナーを見つけるのに大事になってくる、お金や可動日数の入力を必須にし、そこをソート出来るようにしました。
またポートフォリオのURLやポートフォリオ画像も数点貼れるようにしときました。

あと、スペースはなるべく統一して作りました。
例えば上記リストページはiPhoneのファーストビューで自己紹介をMax数書いても2つのリストは最低でも見せれるように空きを調整しました。
空きをきちんと取ることにより、見た目が綺麗に見える?感じがします。
あとは実際に作りながらかなり調整していきました。

開発するプラットフォーム選び

スクリーンショット 2019-05-05 8.35.35.png
フロントエンドの技術だけでアプリが開発できるプラットフォームとして国内で開発している会社として有名な Monaca を選びました。
フロントエンドだけのアプリ開発も徐々に選択できるようになりましたが、自分はこのMonacaのプラットフォームを利用して良かったと思うところは、日本語のドキュメントが充実している所です。
国内で開発している会社なので当たり前かもしれませんが、日頃英語のドキュメント見るのが当たり前なので、日本語のドキュメントが充実しているのは何より新鮮でしたし、大変助かりました。
あと国内産ってなぜか安心するんですよね、まー食べませんが( º﹃º` )…… はい。

ちなみに当たり前ですが、お問い合わせも日本語で出来るのでこれも非常に助かります。
ただしお問い合わせがテクニカルだと、お金をがっつり取られる場合があるのでそこは注意していただきたいです。

興味がある方は、下記料金プランを見ていただけると大体いくら掛かるのかが分かります。
https://ja.monaca.io/pricing.html

使用したバックエンドサービス

スクリーンショット 2019-05-05 8.51.51.png
Qiitaでもかなりの頻度で取り上げられる Firebase を使用しました。
Firebaseで利用したプロダクトは下記4つで、
- データベースの用意として「Realtime Database
- 画像などのデータアップ先として「Cloud Storage
- その次がSNS認証として「Authentication
- あと一部アプリからデータを送信する技術を使用しているため「Cloud Functions
以上のプロダクトを用いて開発しました。
見て分かるように、Firebase一つで多種多様なプロダクトを使用できるので大変助かります。
話が少しそれるのですがFirebaseの中で色々なプロダクトが年々増えてきているのですが、最近気になるのが Google の機械学習技術を用いた「ML Kit
まだベータなのですが、このAPIを利用することによテキスト認識(OCR)はもちろん顔認識を利用した技術も使用することが出来ます。
Firebaseの母体はGoogleなので、Googleで開発された技術がFirebaseでも使用できるのも嬉しいですね。

・データベースのセキュリティについて
Firebase Realtime Databaseではセキュリティ設定を細かく設定することができますが、、、ここで唐突に問題です!
管理権限を持たない一般ユーザは下記 grandchild のルートには読み取りアクセスできますでしょうか?

{  
   "rules":{  
      ".read":false,
      "parent":{  
         "child":{  
            ".read":true,
            "grandchild":{  
               ".read":false
            }
         }
      }
   }
}





正解は「出来ます」
なぜならその親の child ルートで読み取りを許可したので、その権限が子に引き継かれるからです。
なので読み取り先である grandchild の読み取りを不可にしても、親のアクセス権限が適用されます。

ということは仮にトップルートで読み取りがアクセス許可されていた場合は、いくら子が読み取りアクセス不可にしても全体にアクセスできてしまうことになります。

{  
   "rules":{  
      ".read":true,
      "parent":{  
        "child":{  
        //アクセス出来てしまう 
        ".read":false,
            "grandchild":{  
              //アクセス出来てしまう 
              ".read":false
            }
         }
      }
   }
}

まーこんなことしないでしょうが。。

このようにアクセス権限は親ルートにアクセス権限をもたせた場合、それは子に影響されます。
なので今回作ったアプリではアクセス出来るルート権限ごとに細かく分けてルールを定義し、権限通りに動いてるかチェック表をつけました。
スクリーンショット 2019-05-05 11.19.30.png
ご存知の方も多いと思いますが、Firebaseではデータのアクセス権限の確認をコンソールからシミュレートすることが出来ます。
スクリーンショット 2019-05-05 16.36.38.png

より詳しく知りたい方は、下記ドキュメントを見てください。
https://firebase.google.com/docs/database/security/securing-data?hl=ja#read_and_write_rules_cascade


・メール認証について
今回ログイン認証としてパスワード認証メール認証を組み合わせてログインできるようにしてます。
メール認証はログイン後に下記方法で送ることが出来ます。

firebase.auth().currentUser.sendEmailVerification().then(function() { 
  //success
}).catch(function(error) { 
  window.alert(error); 
}); 

送られてきたメールのパラメータには mode や oobCode、apiKeyが付属してます。
メール認証の場合は mode は 'verifyEmail'になります。
他にもパスワード変更やメールアドレス変更などの際の mode があります。
参照 : https://firebase.google.com/docs/auth/custom-email-handler#create_the_email_action_handler_page

例えばメール認証の一例として

auth.checkActionCode(actionCode).then(function() { 
  //ワンタイムコード(oobCode)の確認
  auth.applyActionCode(actionCode).then(function() { 
    //メールアドレス認証を確認
  }).catch(function(error) { 
      window.alert(error); 
  }); 
}).catch(function(error) {  
  window.alert(error);
}); 

checkActionCodeでワンタイムコードを確認し有効であれば、applyActionCodeにてメールアドレス認証を確認することができます。

実際にメール認証されたかどうかは、Firebaseのログイン認証から一度ログアウトする必要があります。
メール認証の確認は firebase.auth().currentUser.emailVerified を使用します。

firebase.auth().signOut().then(function(){ 
  firebase.auth().signInWithEmailAndPassword(email, pass).then(function (info) { 
    if(firebase.auth().currentUser.emailVerified) { 
      //メールアドレス認証済み 
    } else { 
      //メールアドレス認証エラー 
    } 
  }).catch(function (error) { 
    window.alert(error); 
  }); 
}); 


使用したJSフレームワーク

スクリーンショット 2019-05-05 9.20.04.png
おなじみの Vue.js、今回SPAで開発しているためにVue.jsでコーディングさせていただきました。
またSPAを構築する際に Vue Router を使用するかと思いますが、自分は知らなかったので共有として下記方法で一つのコンポーネントに対して複数のパス(alias)を関連付けることもできます。

const Vue = require('vue');
const VueRouter = require('vue-router');
const Main = require('./Main');

Vue.use(VueRouter);

const routes = [{
  path: '/main',
  component: Main,
  alias: ['/page1', '/page2', '/page3']
}];

基本的に path と component は対になってますが、例えば alias に設定した /page1 にアクセスした際に component の Main を共有して使うことが出来ます。
ユーザーから見ると /main と /page1 は別々のURLの為に当然別のページを見てると思うのですが、裏側では共通のページに見ていることになります。

Appleからの審査について

スクリーンショット 2019-05-05 13.48.09.jpg
今回アプリの審査で2回リジェクトを食らったのですが、作ったのがSNSアプリということもあり下記基準に満たしていませんでした。
スクリーンショット 2019-05-05 13.56.02.png
これは書いてあるように、ユーザーがユーザーに対して不適切な行為をされた場合、それを防ぐ/報告手段を実装しなければならいということでした。
そこでユーザーのブロック機能と報告機能を実装して報告したところ、無事通りました。
rb.jpg

最後に

このEndeLinkはApple Storeに公開されようやくスタートしたばかりなので、機能拡張やデザイン改修も含めてこれからやりたいことだらけです。

あともし可能であればぜひ知り合いのデザイナーさんやエンジニアさんに紹介してもらえると有り難いです( ´^`° )

以上、読んで頂きありがとうございました。
また「いいね」を押していただけると大変励みになります(っ_ _)っ


スクリーンショット 2019-05-06 11.25.20.png

※Firebaseの料金プランの兼ね合いから、会員数によって会員登録に制限をかける可能性があります。
※今の所、このアプリは全て無料でご利用できます(広告無)

バグ報告/ご意見は、Twitterからダイレクトメッセージにてご連絡ください!
※些細なことでも言っていただけると嬉しいです(´∩ω∩`)
※唯の批判などはスルーします、人としても。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エンジニアとデザイナー向けのSNSアプリを作りました!【会員登録が80人超えました!感謝(>人<)】

ende_1.jpg
気づいたら10連休最終日!!
会社員になって中々まとまった休みが無い中、やってきたゴールデン10連休!!!

ここぞとばかり徹夜でアプリ作成に挑戦し、つい先日Appleの審査が通り本日リリースを迎えることが出来ました!!
何とも言えない達成感です。

その紹介も兼ねて、どういった技術を使用してこのアプリを作ったのかを簡単にまとめましたので読んでいただけると嬉しくて飛び跳ねます。

EndeLinkとは

Apple Storeの紹介にも記載してますが、このアプリはデザイナーとエンジニアに特化したお仕事探しアプリです。登録されたエンジニアまたはデザイナーの作品、金額、頻度で適切な仕事パートナーを探し出すことができます。
つまり、読んで字のごとくエンジニアとデザイナーを探すのにフォーカスしたSNSアプリです。

作った背景

昔、フリーランスを少しかじっていた時期があるのですが、知人のエンジニアやデザイナーさんに頼みたいけど金額面で気を使わせたり、可動日数が合わず調整が難しかったり…苦労しました…。
その頃からエンジニアやデザイナーさんを探すことに注力した良い感じのSNSをいつか作りたいなと思っていました。
現在はフリーではなく会社員ですが、会社が副業OKなので自分も仕事相手を探す機会も出てくるだろうと思い、思い切ってこの10連休を活かして開発しようと思いました。

EndeLinkはどのようにして作られたのか

ende_board.png

デザイン

スクリーンショット 2019-05-05 9.27.34.png
色々コーディングをやってきましたが、デザインを作ったことは一度もなくセンスもないと認識しているためにAdobe XDでちゃちゃっとワイヤーフレームを作りました。
(軌道に乗れば、デザイナーさんにちゃんと制作を依頼したいです)
一番注意して作ったのが、このアプリの使用目的を明確にすることです。
そこでこのアプリは仕事パートナーを見つけるのに大事になってくる、お金や可動日数の入力を必須にし、そこをソート出来るようにしました。
またポートフォリオのURLやポートフォリオ画像も数点貼れるようにしときました。

あと、スペースはなるべく統一して作りました。
例えば上記リストページはiPhoneのファーストビューで自己紹介をMax数書いても2つのリストは最低でも見せれるように空きを調整しました。
空きをきちんと取ることにより、見た目が綺麗に見える?感じがします。
あとは実際に作りながらかなり調整していきました。

開発するプラットフォーム選び

スクリーンショット 2019-05-05 8.35.35.png
フロントエンドの技術だけでアプリが開発できるプラットフォームとして国内で開発している会社として有名な Monaca を選びました。
フロントエンドだけのアプリ開発も徐々に選択できるようになりましたが、自分はこのMonacaのプラットフォームを利用して良かったと思うところは、日本語のドキュメントが充実している所です。
国内で開発している会社なので当たり前かもしれませんが、日頃英語のドキュメント見るのが当たり前なので、日本語のドキュメントが充実しているのは何より新鮮でしたし、大変助かりました。
あと国内産ってなぜか安心するんですよね、まー食べませんが( º﹃º` )…… はい。

ちなみに当たり前ですが、お問い合わせも日本語で出来るのでこれも非常に助かります。
ただしお問い合わせがテクニカルだと、お金をがっつり取られる場合があるのでそこは注意していただきたいです。

興味がある方は、下記料金プランを見ていただけると大体いくら掛かるのかが分かります。
https://ja.monaca.io/pricing.html

使用したバックエンドサービス

スクリーンショット 2019-05-05 8.51.51.png
Qiitaでもかなりの頻度で取り上げられる Firebase を使用しました。
Firebaseで利用したプロダクトは下記4つで、
- データベースの用意として「Realtime Database
- 画像などのデータアップ先として「Cloud Storage
- その次がSNS認証として「Authentication
- あと一部アプリからデータを送信する技術を使用しているため「Cloud Functions
以上のプロダクトを用いて開発しました。
見て分かるように、Firebase一つで多種多様なプロダクトを使用できるので大変助かります。
話が少しそれるのですがFirebaseの中で色々なプロダクトが年々増えてきているのですが、最近気になるのが Google の機械学習技術を用いた「ML Kit
まだベータなのですが、このAPIを利用することによテキスト認識(OCR)はもちろん顔認識を利用した技術も使用することが出来ます。
Firebaseの母体はGoogleなので、Googleで開発された技術がFirebaseでも使用できるのも嬉しいですね。

・データベースのセキュリティについて
Firebase Realtime Databaseではセキュリティ設定を細かく設定することができますが、、、ここで唐突に問題です!
管理権限を持たない一般ユーザは下記 grandchild のルートには読み取りアクセスできますでしょうか?

{  
   "rules":{  
      ".read":false,
      "parent":{  
         "child":{  
            ".read":true,
            "grandchild":{  
               ".read":false
            }
         }
      }
   }
}





正解は「出来ます」
なぜならその親の child ルートで読み取りを許可したので、その権限が子に引き継かれるからです。
なので読み取り先である grandchild の読み取りを不可にしても、親のアクセス権限が適用されます。

ということは仮にトップルートで読み取りがアクセス許可されていた場合は、いくら子が読み取りアクセス不可にしても全体にアクセスできてしまうことになります。

{  
   "rules":{  
      ".read":true,
      "parent":{  
        "child":{  
        //アクセス出来てしまう 
        ".read":false,
            "grandchild":{  
              //アクセス出来てしまう 
              ".read":false
            }
         }
      }
   }
}

まーこんなことしないでしょうが。。

このようにアクセス権限は親ルートにアクセス権限をもたせた場合、それは子に影響されます。
なので今回作ったアプリではアクセス出来るルート権限ごとに細かく分けてルールを定義し、権限通りに動いてるかチェック表をつけました。
スクリーンショット 2019-05-05 11.19.30.png
ご存知の方も多いと思いますが、Firebaseではデータのアクセス権限の確認をコンソールからシミュレートすることが出来ます。
スクリーンショット 2019-05-05 16.36.38.png

より詳しく知りたい方は、下記ドキュメントを見てください。
https://firebase.google.com/docs/database/security/securing-data?hl=ja#read_and_write_rules_cascade


・メール認証について
今回ログイン認証としてパスワード認証メール認証を組み合わせてログインできるようにしてます。
メール認証はログイン後に下記方法で送ることが出来ます。

firebase.auth().currentUser.sendEmailVerification().then(function() { 
  //success
}).catch(function(error) { 
  window.alert(error); 
}); 

送られてきたメールのパラメータには mode や oobCode、apiKeyが付属してます。
メール認証の場合は mode は 'verifyEmail'になります。
他にもパスワード変更やメールアドレス変更などの際の mode があります。
参照 : https://firebase.google.com/docs/auth/custom-email-handler#create_the_email_action_handler_page

例えばメール認証の一例として

auth.checkActionCode(actionCode).then(function() { 
  //ワンタイムコード(oobCode)の確認
  auth.applyActionCode(actionCode).then(function() { 
    //メールアドレス認証を確認
  }).catch(function(error) { 
      window.alert(error); 
  }); 
}).catch(function(error) {  
  window.alert(error);
}); 

checkActionCodeでワンタイムコードを確認し有効であれば、applyActionCodeにてメールアドレス認証を確認することができます。

実際にメール認証されたかどうかは、Firebaseのログイン認証から一度ログアウトする必要があります。
メール認証の確認は firebase.auth().currentUser.emailVerified を使用します。

firebase.auth().signOut().then(function(){ 
  firebase.auth().signInWithEmailAndPassword(email, pass).then(function (info) { 
    if(firebase.auth().currentUser.emailVerified) { 
      //メールアドレス認証済み 
    } else { 
      //メールアドレス認証エラー 
    } 
  }).catch(function (error) { 
    window.alert(error); 
  }); 
}); 


使用したJSフレームワーク

スクリーンショット 2019-05-05 9.20.04.png
おなじみの Vue.js、今回SPAで開発しているためにVue.jsでコーディングさせていただきました。
またSPAを構築する際に Vue Router を使用するかと思いますが、自分は知らなかったので共有として下記方法で一つのコンポーネントに対して複数のパス(alias)を関連付けることもできます。

const Vue = require('vue');
const VueRouter = require('vue-router');
const Main = require('./Main');

Vue.use(VueRouter);

const routes = [{
  path: '/main',
  component: Main,
  alias: ['/page1', '/page2', '/page3']
}];

基本的に path と component は対になってますが、例えば alias に設定した /page1 にアクセスした際に component の Main を共有して使うことが出来ます。
ユーザーから見ると /main と /page1 は別々のURLの為に当然別のページを見てると思うのですが、裏側では共通のページを見ていることになります。

Appleからの審査について

スクリーンショット 2019-05-05 13.48.09.jpg
今回アプリの審査で2回リジェクトを食らったのですが、作ったのがSNSアプリということもあり下記基準に満たしていませんでした。
スクリーンショット 2019-05-05 13.56.02.png
これは書いてあるように、ユーザーがユーザーに対して不適切な行為をされた場合、それを防ぐ/報告手段を実装しなければならいということでした。
そこでユーザーのブロック機能と報告機能を実装して報告したところ、無事通りました。
rb.jpg

最後に

このEndeLinkはApple Storeに公開されようやくスタートしたばかりなので、機能拡張やデザイン改修も含めてこれからやりたいことだらけです。

あともし可能であればぜひ知り合いのデザイナーさんやエンジニアさんに紹介してもらえると有り難いです( ´^`° )

以上、読んで頂きありがとうございました。
また「いいね」を押していただけると大変励みになります(っ_ _)っ


スクリーンショット 2019-05-06 11.25.20.png

※Firebaseの料金プランの兼ね合いから、会員数によって会員登録に制限をかける可能性があります。
※今の所、このアプリは全て無料でご利用できます(広告無)

バグ報告/ご意見は、Twitterからダイレクトメッセージにてご連絡ください!
※些細なことでも言っていただけると嬉しいです(´∩ω∩`)
※唯の批判などはスルーします、人としても。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エンジニアとデザイナー向けのSNSアプリを作りました!

ende_1.jpg
気づいたら10連休最終日!!
会社員になって中々まとまった休みが無い中、やってきたゴールデン10連休!!!

ここぞとばかり徹夜でアプリ作成に挑戦し、つい先日Appleの審査が通り本日リリースを迎えることが出来ました!!
何とも言えない達成感です。

その紹介も兼ねて、どういった技術を使用してこのアプリを作ったのかを簡単にまとめましたので読んでいただけると嬉しくて飛び跳ねます。

EndeLinkとは

Apple Storeの紹介にも記載してますが、このアプリはデザイナーとエンジニアに特化したお仕事探しアプリです。登録されたエンジニアまたはデザイナーの作品、金額、頻度で適切な仕事パートナーを探し出すことができます。
つまり、読んで字のごとくエンジニアとデザイナーを探すのにフォーカスしたSNSアプリです。

作った背景

昔、フリーランスを少しかじっていた時期があるのですが、知人のエンジニアやデザイナーさんに頼みたいけど金額面で気を使わせたり、可動日数が合わず調整が難しかったり…苦労しました…。
その頃からエンジニアやデザイナーさんを探すことに注力した良い感じのSNSをいつか作りたいなと思っていました。
現在はフリーではなく会社員ですが、会社が副業OKなので自分も仕事相手を探す機会も出てくるだろうと思い、思い切ってこの10連休を活かして開発しようと思いました。

EndeLinkはどのようにして作られたのか

ende_board.png

デザイン

スクリーンショット 2019-05-05 9.27.34.png
色々コーディングをやってきましたが、デザインを作ったことは一度もなくセンスもないと認識しているためにAdobe XDでちゃちゃっとワイヤーフレームを作りました。
(軌道に乗れば、デザイナーさんにちゃんと制作を依頼したいです)
一番注意して作ったのが、このアプリの使用目的を明確にすることです。
そこでこのアプリは仕事パートナーを見つけるのに大事になってくる、お金や可動日数の入力を必須にし、そこをソート出来るようにしました。
またポートフォリオのURLやポートフォリオ画像も数点貼れるようにしときました。

あと、スペースはなるべく統一して作りました。
例えば上記リストページはiPhoneのファーストビューで自己紹介をMax数書いても2つのリストは最低でも見せれるように空きを調整しました。
空きをきちんと取ることにより、見た目が綺麗に見える?感じがします。
あとは実際に作りながらかなり調整していきました。

開発するプラットフォーム選び

スクリーンショット 2019-05-05 8.35.35.png
フロントエンドの技術だけでアプリが開発できるプラットフォームとして国内で開発している会社として有名な Monaca を選びました。
フロントエンドだけのアプリ開発も徐々に選択できるようになりましたが、自分はこのMonacaのプラットフォームを利用して良かったと思うところは、日本語のドキュメントが充実している所です。
国内で開発している会社なので当たり前かもしれませんが、日頃英語のドキュメント見るのが当たり前なので、日本語のドキュメントが充実しているのは何より新鮮でしたし、大変助かりました。
あと国内産ってなぜか安心するんですよね、まー食べませんが( º﹃º` )…… はい。

ちなみに当たり前ですが、お問い合わせも日本語で出来るのでこれも非常に助かります。
ただしお問い合わせがテクニカルだと、お金をがっつり取られる場合があるのでそこは注意していただきたいです。

興味がある方は、下記料金プランを見ていただけると大体いくら掛かるのかが分かります。
https://ja.monaca.io/pricing.html

使用したバックエンドサービス

スクリーンショット 2019-05-05 8.51.51.png
Qiitaでもかなりの頻度で取り上げられる Firebase を使用しました。
Firebaseで利用したプロダクトは下記4つで、
- データベースの用意として「Realtime Database
- 画像などのデータアップ先として「Cloud Storage
- その次がSNS認証として「Authentication
- あと一部アプリからデータを送信する技術を使用しているため「Cloud Functions
以上のプロダクトを用いて開発しました。
見て分かるように、Firebase一つで多種多様なプロダクトを使用できるので大変助かります。
話が少しそれるのですがFirebaseの中で色々なプロダクトが年々増えてきているのですが、最近気になるのが Google の機械学習技術を用いた「ML Kit
まだベータなのですが、このAPIを利用することによテキスト認識(OCR)はもちろん顔認識を利用した技術も使用することが出来ます。
Firebaseの母体はGoogleなので、Googleで開発された技術がFirebaseでも使用できるのも嬉しいですね。

・データベースのセキュリティについて
Firebase Realtime Databaseではセキュリティ設定を細かく設定することができますが、、、ここで唐突に問題です!
管理権限を持たない一般ユーザは下記 grandchild のルートには読み取りアクセスできますでしょうか?

{  
   "rules":{  
      ".read":false,
      "parent":{  
         "child":{  
            ".read":true,
            "grandchild":{  
               ".read":false
            }
         }
      }
   }
}





正解は「出来ます」
なぜならその親の child ルートで読み取りを許可したので、その権限が子に引き継かれるからです。
なので読み取り先である grandchild の読み取りを不可にしても、親のアクセス権限が適用されます。

ということは仮にトップルートで読み取りがアクセス許可されていた場合は、いくら子が読み取りアクセス不可にしても全体にアクセスできてしまうことになります。

{  
   "rules":{  
      ".read":true,
      "parent":{  
        "child":{  
        //アクセス出来てしまう 
        ".read":false,
            "grandchild":{  
              //アクセス出来てしまう 
              ".read":false
            }
         }
      }
   }
}

まーこんなことしないでしょうが。。

このようにアクセス権限は親ルートにアクセス権限をもたせた場合、それは子に影響されます。
なので今回作ったアプリではアクセス出来るルート権限ごとに細かく分けてルールを定義し、権限通りに動いてるかチェック表をつけました。
スクリーンショット 2019-05-05 11.19.30.png
ご存知の方も多いと思いますが、Firebaseではデータのアクセス権限の確認をコンソールからシミュレートすることが出来ます。
スクリーンショット 2019-05-05 16.36.38.png

より詳しく知りたい方は、下記ドキュメントを見てください。
https://firebase.google.com/docs/database/security/securing-data?hl=ja#read_and_write_rules_cascade


・メール認証について
今回ログイン認証としてパスワード認証メール認証を組み合わせてログインできるようにしてます。
メール認証はログイン後に下記方法で送ることが出来ます。

firebase.auth().currentUser.sendEmailVerification().then(function() { 
  //success
}).catch(function(error) { 
  window.alert(error); 
}); 

送られてきたメールのパラメータには mode や oobCode、apiKeyが付属してます。
メール認証の場合は mode は 'verifyEmail'になります。
他にもパスワード変更やメールアドレス変更などの際の mode があります。
参照 : https://firebase.google.com/docs/auth/custom-email-handler#create_the_email_action_handler_page

例えばメール認証の一例として

auth.checkActionCode(actionCode).then(function() { 
  //ワンタイムコード(oobCode)の確認
  auth.applyActionCode(actionCode).then(function() { 
    //メールアドレス認証を確認
  }).catch(function(error) { 
      window.alert(error); 
  }); 
}).catch(function(error) {  
  window.alert(error);
}); 

checkActionCodeでワンタイムコードを確認し有効であれば、applyActionCodeにてメールアドレス認証を確認することができます。

実際にメール認証されたかどうかは、Firebaseのログイン認証から一度ログアウトする必要があります。
メール認証の確認は firebase.auth().currentUser.emailVerified を使用します。

firebase.auth().signOut().then(function(){ 
  firebase.auth().signInWithEmailAndPassword(email, pass).then(function (info) { 
    if(firebase.auth().currentUser.emailVerified) { 
      //メールアドレス認証済み 
    } else { 
      //メールアドレス認証エラー 
    } 
  }).catch(function (error) { 
    window.alert(error); 
  }); 
}); 


使用したJSフレームワーク

スクリーンショット 2019-05-05 9.20.04.png
おなじみの Vue.js、今回SPAで開発しているためにVue.jsでコーディングさせていただきました。
またSPAを構築する際に Vue Router を使用するかと思いますが、自分は知らなかったので共有として下記方法で一つのコンポーネントに対して複数のパス(alias)を関連付けることもできます。

const Vue = require('vue');
const VueRouter = require('vue-router');
const Main = require('./Main');

Vue.use(VueRouter);

const routes = [{
  path: '/main',
  component: Main,
  alias: ['/page1', '/page2', '/page3']
}];

基本的に path と component は対になってますが、例えば alias に設定した /page1 にアクセスした際に component の Main を共有して使うことが出来ます。
ユーザーから見ると /main と /page1 は別々のURLの為に当然別のページを見てると思うのですが、裏側では共通のページを見ていることになります。

Appleからの審査について

スクリーンショット 2019-05-05 13.48.09.jpg
今回アプリの審査で2回リジェクトを食らったのですが、作ったのがSNSアプリということもあり下記基準に満たしていませんでした。
スクリーンショット 2019-05-05 13.56.02.png
これは書いてあるように、ユーザーがユーザーに対して不適切な行為をされた場合、それを防ぐ/報告手段を実装しなければならいということでした。
そこでユーザーのブロック機能と報告機能を実装して報告したところ、無事通りました。
rb.jpg

最後に

このEndeLinkはApple Storeに公開されようやくスタートしたばかりなので、機能拡張やデザイン改修も含めてこれからやりたいことだらけです。

あともし可能であればぜひ知り合いのデザイナーさんやエンジニアさんに紹介してもらえると有り難いです( ´^`° )

以上、読んで頂きありがとうございました。
また「いいね」を押していただけると大変励みになります(っ_ _)っ


スクリーンショット 2019-05-06 11.25.20.png

※Firebaseの料金プランの兼ね合いから、会員数によって会員登録に制限をかける可能性があります。
※今の所、このアプリは全て無料でご利用できます(広告無)

バグ報告/ご意見は、Twitterからダイレクトメッセージにてご連絡ください!
※些細なことでも言っていただけると嬉しいです(´∩ω∩`)
※唯の批判などはスルーします、人としても。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AVSpeechSynthesizerでの初回音声読み上げが遅いのを直す

iOSで音声読み上げをする時のコード。

import AVFoundation

class SpeechViewController: UIViewController {
    private let synthesizer = AVSpeechSynthesizer()

    private func speech(_ text: String) {
        // 初回のみ0.1~2秒遅れて読み上げられる
        let utterance = AVSpeechUtterance(string: text)
        synthesizer.speak(utterance)
    }

ただこれだと初回の読み上げのみ0.1~2秒遅れて読み上げられる。
2回目以降は遅延なく読み上げられる。
なのでviewDidLoadで空文字を1回読んでおく。

import AVFoundation

class SpeechViewController: UIViewController {
    private let synthesizer = AVSpeechSynthesizer()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 空文字を読んでおく
        let utterance = AVSpeechUtterance(string: "")
        utterance.volume = 0
        synthesizer.speak(utterance)
    }

    private func speech(_ text: String) {
        // 遅延なく読み上げられる
        let utterance = AVSpeechUtterance(string: text)
        synthesizer.speak(utterance)
    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

外部決済代行業者にアプリ内課金をさせることができるか

スマホアプリ(iOS/Android)で有料会員のみに一部コンテンツへのアクセスを可能とさせる場合、通常はApple/GoogleにてI/Fが用意されているアプリ内課金の仕組みで実装するのが正攻法と考えられる。

しかし、例えばAmazonのPrime videoなどではアプリ内課金の仕組みは利用されておらず、外部ブラウザにて会員登録をさせる仕組みとなっている。これらの仕様はiOS/Androidそれぞれのディベロッパーポリシー等に違反しないのか、その解釈を調べてみた。

まず結論

下記条件であれば、アプリ内課金を利用しなくても(外部の決済代行業者を利用しても)良いと考えられる。

  • 有料会員の特典は、アプリ外でも利用できる(アプリ内のみのコンテンツではない)
  • 決済画面はアプリ内WebViewよりは、ブラウザアプリで表示させたほうが良い。

判断理由(iOS)

App Store Reviewガイドライン(https://developer.apple.com/jp/app-store/review/guidelines/#in-app-purchase)によると

3.1.5(a)Appの外部で使用する商品やサービス:ユーザーがAppの外部で使用する商品やサービスをAppで購入できるようにする場合、そうした商品の支払いにはApp内課金以外(Apple Payや クレジットカードなど)の方法を使用する必要があります。

とある。つまり、

  • アプリケーションの「内部」で使用する商品やサービス: App内課金での支払いで実装
  • アプリケーションの「外部」で使用する商品やサービス: App内課金以外の方法での支払い(クレジットカード支払いなど)で実装

と考えられる(参考:https://inside.pixiv.blog/danbo-tanaka/4749)。
有料会員の特典適応範囲がアプリ内のみであるとみなされた場合、リジェクト対象となる恐れがある。

判断理由(Android)

デベロッパーポリシー(https://play.google.com/intl/ja/about/developer-content-policy-print/ )では下記と定義されています。

デベロッパーは、Google Play からダウンロードされた別のカテゴリのアプリ内でプロダクトを提供する場合、支払い方法として Google Play アプリ内課金を使用しなければなりません。
ただし、以下の場合を除きます。
・物理的なプロダクトのみの支払い
・そのアプリ以外で消費できるデジタル コンテンツに対する支払い(他の音楽プレーヤーで再生できる曲など)

つまり、基本的な考えはiOSと同じと考えられます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む