位置情報を使ったブラック企業通知アプリをリリースした【個人開発】

ブラック企業を地図にマッピングし、**周辺にブラック企業があればプッシュ通知で知らせてくれる**アプリをリリースしました！

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">位置情報を利用して周辺にブラック企業があればプッシュ通知で知らせてくれるアプリ「ブラックアラート」をリリースしました ！<a href="https://t.co/eqSJpnmy9W">https://t.co/eqSJpnmy9W</a><a href="https://twitter.com/hashtag/%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF%E4%BC%81%E6%A5%AD?src=hash&amp;ref_src=twsrc%5Etfw">#ブラック企業</a> <a href="https://twitter.com/hashtag/%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%88?src=hash&amp;ref_src=twsrc%5Etfw">#ブラックアラート</a> <a href="https://t.co/OkaFtH5zQU">pic.twitter.com/OkaFtH5zQU</a></p>&mdash; ブラック企業通知アプリ@ブラックアラート (@blackalert_app) <a href="https://twitter.com/blackalert_app/status/1084802369693483009?ref_src=twsrc%5Etfw">January 14, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


個人でwebサービスやアプリを開発している人に少しでも何かタメになることがあればと思いサービスを作ろうと思った経緯や使用技術などをずらずらと書いていこうと思います！

## リリースしたサービス
iOS
[ブラックアラート - 周辺ブラック企業プッシュ通知アプリ](https://itunes.apple.com/jp/app/id1447073481)

Android
[ブラックアラート - 周辺ブラック企業プッシュ通知アプリ]
(https://play.google.com/store/apps/details?id=com.ryo.naruse.blackalert)

## どんなアプリ？
位置情報を利用して周辺にブラック企業があればプッシュ通知で知らせてくれるアプリです。

## できること
##### 周辺にブラック企業があればプッシュ通知
<img width="375" alt="notify.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/160183/d255f64f-3836-f1d1-ca51-678263346374.png">

##### ブラック企業の検索
<img width="375" alt="IMG_1635.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/160183/1fc308b4-fcaf-0eee-28ed-cac58f853f02.png">

<img width="375" alt="IMG_1635.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/160183/14822cb5-074f-06a1-262a-909d5d7c1c7f.png">

##### ブラック企業の詳細閲覧、ツイート
<img width="375" alt="IMG_965BC3B1EAA9-1.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/160183/b96930a1-540d-ffbf-452a-8f4578f75402.jpeg">


## 開発経緯
去年、ブラック企業をマッピングした某webサービス様が話題になっていたのがきっかけで自分もiOSアプリで出したいと思いました。(わたしが開発者ではありません。)
ただ、ブラック企業をマッピングして表示するだけではオリジナリティにかけてしまうので**周辺にブラック企業があれば通知するのはどうか**というアイデアから生まれました。

## ブラック企業の基準は？
厚生労働省が公表している「労働基準関係法令違反に係る公表事案」に掲載されている労働基準法等違反で書類送検された企業を指しています。

下記のサイトの「労働基準関係法令違反に係る公表事案」PDFファイルよりダウンロードできます。
[長時間労働削減に向けた取組](https://www.mhlw.go.jp/kinkyu/151106.html)

**私の独断偏見で追加はしておりません**

## 技術周り
以下は技術周りについてです

## 使用技術, 環境
- Swift4
- Realm
- Ruby2.5
- Ruby on Rails 5.2
- GoogleCloudPlatform
  - Maps SDK for iOS
  - Places API 
- Gitlab
- Amazon s3
- Firebase Analytics

# PDFのデータをcsvに変換
当アプリはAmazon s3にブラック企業一覧csvを配置し、ダウンロードしてRealmに保存しています。

対象PDF([労働基準関係法令違反に係る公表事案](https://www.mhlw.go.jp/kinkyu/dl/180928.pdf))をExcelに変換します。
[smallpdf](https://smallpdf.com/jp/pdf-to-excel)というサイトでPDFからExcelに変換しました。(他に何か良い方法あれば教えてください・・・！)

変換したExcelをRuby, Railsでcsvに書き出します。

- Excelを扱うGem
 - [roo](https://github.com/roo-rb/roo)

<img width="989" alt="スクリーンショット 2019-01-14 3.12.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/160183/4a95a163-322f-ded9-fed8-4bfcbe34861f.png">

Excel化した各項目をcsvとして書き出します。

## 所在地から緯度経度を取得
Maps SDK for iOS にて地図にピンを配置するには、緯度経度の情報が必要です。
そのため、Places API を使いました。

- 使ったGem
 - [google_places](https://github.com/qpowell/google_places)

こんな感じで簡単に緯度経度を取得できます。

```ruby
result = @client.spots_by_query('東京都港区...')
```

## 完成CSV
最終的に下記のようなcsvとしAmazonS3にアップロードします。

|id       |       name |    address    | longitude        | latitude        | public_date | detail| etc
|:-----------------|------------------:|:-----------------|:------------------:|:------------------:|:------------------:|:-----------------|:-----------------|:-----------------|
|1|hogeカンパニー|東京都港区...| 142.357 | 43.2 |H29.6.15|トラクター・ショベルの運転を無資格の労働者に行わせたもの|H30.2.5送検
|2|fugaコーポレーション|東京都豊島区..| 143.357 | 43.3 |H29.6.17|フォークリフトに接触するおそれがある箇所に労働者を立ち入らせたもの|H30.2.5送検
| ...|...|...|...|...|...|...|...

## csvをダウンロードしRealmに保存
アプリ起動時の初回のみcsvをダウンロードし、csvの各カラムをRealmに保存し、ブラック企業を配置します。
※１日に１度だけcsvを再度ダウンロードし、増減チェックしてあれば更新するようにしています。

``` Swift
// ブラック企業モデル
import RealmSwift

class Company: Object {
    let id = RealmOptional<Int>()
    @objc dynamic var name: String? = nil
    @objc dynamic var address: String? = nil
    let longitude = RealmOptional<Double>()
    let latitude = RealmOptional<Double>()
    @objc dynamic var public_date: String? = nil
    @objc dynamic var law: String? = nil
    @objc dynamic var detail: String? = nil
    @objc dynamic var etc: String? = nil
    
    @objc dynamic var notification: CompanyNotification?
}
```

``` Swift
// 取り込み
let importBycompanies = List<Company>()

// csvをparseしてeach
for csvCompany in csvCompanyRows {
    let company = Company()
    company.id.value = id
    company.name = name
    company.address = address
    company.longitude.value = longitude
    company.latitude.value = latitude
    company.public_date = public_date
    company.law = law
    company.detail = detail
    company.etc = etc

    importBycompanies.append(company)
}

// 書き込み
let realm = try! Realm()
try! realm.write {
    for company in importBycompanies {
        realm.add(company)
    }
}
````

## プッシュ通知条件
現在地が更新されたタイミングで一番近いブラック企業が一定の圏内にあれば通知しています。
また、何度も同じブラック企業の通知を防ぐために一度通知したブラック企業は２４時間再通知をしません。

## 使用したGemやライブラリ
- Swift
 - [TwitterKit](https://github.com/twitter/twitter-kit-ios)
 ブラック企業の詳細情報をツイート
 - [SearchTextField](https://github.com/apasccon/SearchTextField) 
 ブラック企業検索でサジェストさせる
 - [PopupDialog](https://github.com/orderella/PopupDialog) 
 自作のviewcontrollerをモーダルとして表示できる。(検索モーダルで使用)

追記：随時更新予定。
質問などここらへんもっと詳しく説明して欲しいなどあればお気軽にどうぞ！(長文書き慣れていないので端折ってた部分とかあるのでw)