素振り用iOSプロジェクト fcm編

前回

素振り用iOSプロジェクト fastlane match編 - kz-kazuki’s blog

今回のゴール

firebase cloud messaging(以下fcm)を使ってpush通知を送ることができる

firebaseのドキュメント読んでポチポチすれば終わるが...

firebase

新しくプロジェクトを作成する

f:id:assaulter:20200808164038p:plain

iOSボタンを押すと進むので指示通りに作業

f:id:assaulter:20200808164133p:plain

現時点ではまだPod推奨なので、*.xcworkspace から起動することになる

fastlaneでapns用証明書を作成する

fastlane/Fastfileにコマンドを追加 (bundle_idをAppFileに記述してるので不要

...
    desc "create develop apns cert."
    lane :create_apns_develop do
        pem(
            force: true,
            development: true,
            save_private_key: true
        )
    end

コマンドを実行する

...
[16:51:12]: Creating a new push certificate for app 'org.assaulter.base'.
Private key, p12 certificate, PEMが保存されている旨が表示
...

.p12をfirebaseにアップロード

(p8がfastlaneで作れるか調べてない。できるならそっちのほうが楽

firebase console > プロジェクトを設定 > クラウドメッセージング で、開発用APNs証明書としてアップロードする

push notificationが使えるようにする

xcode > Signing & Capabilities で Push Notificationss を追加する

以下のコマンドを追加し実行

    desc "renew develop provisioning profile."
    lane :force_develop do
        match(type: "development", force: true)
    end
$ bundle exec fastlane force_develop

dev centerでidentifierが更新されていることを確認する

push許諾とfcm連携

一旦AppDelegateに実装を追加する

import UIKit
import Firebase
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
        
        registerRemoteNotification()
        
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
}

// MARK: - private

private extension AppDelegate {
    
    /// テスト用なのでcompletionは特に何もしない
    func registerRemoteNotification() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions, completionHandler: { granted, error in
                if granted {
                    DispatchQueue.main.async {
                        UIApplication.shared.registerForRemoteNotifications()
                    }
                }
        })
    }
}

// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let deviceTokenString: String = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
        debugPrint("deviceTokenString \(deviceTokenString)")
    }
    
    func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {
        debugPrint("リモート通知の設定は拒否されました")
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        let userInfo = notification.request.content.userInfo
        debugPrint("userInfo: \(userInfo)")

        completionHandler([.alert, .sound])
    }
}

// MARK: - MessagingDelegate

extension AppDelegate: MessagingDelegate {
    
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        debugPrint("fcmToken: \(fcmToken)")
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }
}

実機でアプリを起動し、許諾を承認するとfcmTokenがログに出る

fcm http api v1を使って動作確認

firebase console > プロジェクトの設定 > サービスアカウント > Firebase Admin SDK > 「新しい秘密鍵を生成」を押す

落ちてきたjsonファイルは保管しておく

認証とリクエストを行うrubyスクリプト

雑に

# frozen_string_literal: true

source "https://rubygems.org"

gem "google-api-client"
gem "faraday"
gem "googleauth"
require 'bundler'
Bundler.require
require 'json'

# Config
file_path = "service account key file path"
project_id = "Your firebase project id"
token = "fcmToken from app."

# get access token
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
    json_key_io: File.open(file_path),
    scope: 'https://www.googleapis.com/auth/firebase.messaging'
)
access_token = authorizer.fetch_access_token!
access_key = "#{access_token['token_type']} #{access_token['access_token']}"

# request
uri = URI.parse("https://fcm.googleapis.com/v1/projects/#{project_id}/messages:send")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = 'application/json'
req['Authorization'] = access_key
req.body = {
    message: {
        token: token,
        notification: {
            title: 'test push notification',
            body: 'notification message from fcm.'
        }
    }
}.to_json

res = https.request(req)
p res

configの部分を埋めて実行するとpushが飛ぶのを確認できる

素振り用iOSプロジェクト fastlane match編

概要

fastlane matchのドキュメントに書いてあることをかいつまんで実行

環境

Xcode 11.5

手順

Xcode

  • XcodeでSinglePageAppを作成
  • Automatically manage signingのチェックを外す
  • シミュレーターでiPhone/iPadで動くのを確認

fastlane準備


参考:https://qiita.com/shumatsukishu/items/f398a449a07b0bc15e0f

  • Gemfile追加 & Bundle install

fastlane初期化

バージョン:2.154.0

$ bundle exec fastlane init
  • 選択肢が出るのでManual setupを選ぶ
  • /fastlane が作成されることを確認

DevCenterに登録

$ bundle exec fastlane produce -a org.assaulter.base -i
  • IDとMFA聞かれるのでよしなに
  • DevCenterに作成されるのを確認
  • -iを指定しているので、AppStoreConnectには作成されない
  • fastlane/Appfileのapp_identifierとapple_idを埋めておく

実機確認用証明書管理

予めプライベートリポジトリを用意しておく

複数プロジェクトを単一リポジトリで扱うことも可能

$ bundle exec fastlane match init
  • Gitを指定し、urlを入れる(プライベートリポジトリ)
  • MATCH_PASSWORDを設定しておく
    • 今回はenvrcを使った
$ bundle exec fastlane match development
  • Dev centerでcertificateとprovisioning profileができているのを確認
  • 登録済みの実機で動作確認

5月投資振り返り

マザーズ指数だけ見ると完全にコロナなんてなかったことになってますが、これからどうなるんでしょうか

売買履歴振り返り

IBJ

5/1 -> 5/12

5/18 -> 5/21

決算だったんで一旦利確しました。

もうすぐゴールデンクロスな気がするのでまたINしようかなと。

BASE

5/19 売却 S高マイナス10%のところに逆指値置いてたら売れちゃいました。 3,000円割れないですねー

イー・ギャランティ

5/18 購入 短期移動平均線近くまで下げたので購入。割高感はあるのであんまり長くホールドはしないかも。

ヤマハ発動機

5/27 -> 5/28 マザーズ -> 東証一部の流れかなと思い割安感があったので購入。 やっぱり決算が怖くて利確。無配になってしまいましたがどうなりますかね。

ほしい銘柄

米株

  • BYND
  • RPAY
  • NET
  • NYSE

ITエンジニアが使うサービスの株買っておけば良いんじゃね理論ですがどれも割高感が。。。

再度暴落が来るのであればQQQに入れて気絶で良いかも。。。

日本株

  • 凸版印刷
    • Shofoo!やってるのに気づかなかった。色々やってるんですね。
  • DMS
    • 暴落前のチャートが良くて業界首位で割安感っていう軽い考え

まとめ

押し目待ちに押し目なし。な一ヶ月でした。

新興国デフォルトとか米中関係とかで暴落来るの待っててだいぶ現金の割合が高いんですが、そうならなかったら適当にETFに突っ込んでまた日常に戻ろうかなと思っています。

4月投資振り返り

COVID-19の影響で完全リモートワークになり、通勤時間が浮いたので、それを投資の勉強?などにあてています。

今まではつみたてNISA米株毎日積立しかやってなかったのですが、恐る恐る個別も買いました。2番底警戒しながらなので、保有現金のうち20%くらいしか突っ込めてなくて悔しい思いをしています。

売買履歴振り返り

三菱UFJ(購入: 3/18, 売却: 3/31)

4年ぶりくらいだったので、肩慣らしに売買。

日経平均の一番底が3/19だったので、タイミングとしてはほぼ完璧だけど銘柄それじゃないだろっていう。

BASE(購入: 3/31)

リアル店舗→ECの流れが強いのでは?ということで割と本命なのでホールド中。shopifyはすんげー上がりましたね。

エアトリ(購入: 4/17, 売却: 4/20)

出遅れを探してて購入したけどやっぱり影響が読めないってことですぐ利確。安い気はするんですけど別にそんなリスク取らなくても良いかな?

ウィルプラスHD(購入: 4/23)

増収増益・小型株・低PERで引っかかったので保有。5/8短信出ましたが一旦大丈夫かな。。。

 

トレードも含めて今の所勝率100%という異常事態なのですが、全然お金入れてないのでもったいないことをしたなぁと。

 

今後の方針

個別株は長期ホールドで大化けを狙いたいと思っています。

一応ITエンジニアなので、IT系小型株を集めていきたいんですが、早速Fastly買おうとしたら5/7決算出て+40%を見送るという事態になりました。先行き不安です。

2019年を振り返る

できごと

転職した

  • iOSの開発が一旦ストップしそう
  • 複数回誘われた

ということでホイホイつられて同じビルの別の階の会社に6月頃転職。

転職を決めてから辞めるまでの間はリソースが足りないこともあり(人員計画がかなりアレだなぁと思う...)サーバーサイドの仕事を結構ゴリゴリやりつつiOSアプリのメンテみたいなことをやってて、これはこれで楽しかったので微妙に後悔したりしなかったり。

僕にしては珍しく、同時期入社の人達と仲良くしてもらってて、人間関係はかなり良好でした(まあ、ほとんど別のところに行っちゃったんですが。またどこかで一緒に仕事したいなと思ってますので今後ともよろしくおねがいします。

新しい職場

途中からマネージャーが加わってすごく良くなった。加わる前は正直かなり酷くてどうしたもんかと思いつつも、歴史あるプロダクトに機能を付け加えたりなんたりするのに必死だったので一瞬で半年が終わってしまった。

来年からまた組織変わるっぽくて、せっかくうまくドライブするようになってきたのになーという感情がある。

転職について

複数回やると慣れちゃって完全に抵抗がなくなるので、それはそれで良くないなぁと思ったり。

デメリットは明確で、とにかく手続き関係がダルい。

特に企業型確定拠出年金制度があるところから無いところに移動する際にiDeCoに切り替えるんですが、ブランクが長くて機会損失半端なさすぎて呆れました。

職場の立地など

高速エレベーターがあるような高層ビルに対してかなりネガティブになってしまった。

もともと気圧の変化に弱いので、今後職場を選ぶときはオフィスビルも考慮材料になりそう。。。

キャリアなど

来期から徐々に人も見るようになっていくらしいのでまずはそれをやってから考えようと思ってます。

サラリーマンの給与の期待値になるとやっぱりエンジニアリング + ナニカというのが王道なんでしょうか。

労働について

就職してから今まで多分2週間以上の長い休みというものを取ったことがなく、ちょっと疲れてきたのかもしれない!

どうもここ1年くらいはネガティブなことを考えがちです。具体的に言うと目標設定から逃避したい。

お金関係

転職などあり自分で売買する精神的余裕がなかったので脳死投資

そろそろ株全ツッパなポートフォリオを見直すときかなと思うんですが、どうでしょうか?

積立NISA

SBIで営業日毎に以下の銘柄を300円ずつ購入。

  • 大和-iFree S&P500インデックス
  • 楽天楽天・全米株式インデックス・ファンド
  • ニッセイ-<購入・換金手数料なし>ニッセイ外国株式インデックスファン
  • ニッセイ-ニッセイ日経225インデックスファンド

上から順にパフォーマンスが良いです。どれも10%強プラスになってる。

iDeCo

  • 楽天・全米株式インデックス・ファンド

9月から開始したのに +8%強で完全にバブル

てか積立NISAと同じ銘柄w

LINEワンコイン投資

  • 週2,000円
  • ポイント付くのでやってみるかの精神

kz-kazuki.hatenadiary.jp

+3%弱とポイント0.8%なので悪くないけどポイント付かなくなったら止めるかも

確か出金に手数料がかかるんすよね。。。

LINEワンコイン投資とクラウドファンディングを申し込んだ

LINEワンコイン投資

  • 実質Folioのサービス
  • 2020年4月まで運用手数料無料
  • LINEマイカラー対象っぽい

とりあえずやってみてポイント取れなくなったら辞めるかな

クラウドファンディング

これらは面白い募集あったら突っ込むかもくらいの温度感

消費税10%まじ怖い

UIPageViewControllerのsetViewControllersでanimated: trueにしつつscrollViewのdelegateを奪い、無理やりbouncesを止めると挙動がおかしくなる件

タイトル長いんですが、無理やりPageViewControllerをいじるとおかしくなったのでメモ。 バージョン上がったらそのうち治るかも & そもそもやり方があれかも。

Image from Gyazo

こういうよくある画面を作ってみた。 PageViewControllerで作っているので、両端にいった場合はbounceする(それでいいっちゃ良いんだけど)。

bouce止める場合はどうするんだろうと思い、「pageviewcontroller bounces stop」でググって出てきたやつを試す

bounce止めたやつ

stackoverflow.com

Image from Gyazo

暫定対応(アニメーションしない)

setViewControllersでanimated: falseにすればおかしくはない(アニメーションしないけど)

Image from Gyazo

スタックオーバーフローをさまようと、PageViewControllerのキャッシュっぽさがあるけどよくわかんなかった。

リポジトリ

github.com