"react-native link" は何をするか

## はじめに
ReactNative で、 npm モジュールを利用する場合、次のように react-native link コマンドを実行する必要がある場合と、ない場合があります。link は一体なにをやっているのでしょうか？

```
# link が不要
$react-native install hoge --save

# link が必要
$react-native install hoge --save
$react-native link hoge
```

## link が必要な場合
link がどんな場合に必要なのかは、 ReactNative の [LinkingLibraries](https://facebook.github.io/react-native/docs/linking-libraries-ios.html) に記載されています。


> All the libraries we ship with React Native live on the Libraries folder in the root of the
> repository. Some of them are pure JavaScript, and you only need to require it. Other libraries
> also rely on some native code, in that case you'll have to add these files to your app, otherwise
> the app will throw an error as soon as you try to use the library.


つまり、Javascript オンリーのモジュールを利用する場合には link は不要だけど、NativeCode を利用する場合には必要ということです。この NativeCode を利用する場合に必要、というのが若干の曲者で、単に Objective-C や、Java で書く必要性がある場合だけでなく、追加するファイルが必要な場合や、Info.plist(iOSのプロジェクト), Gradleファイル(Androidのプロジェクト）を変更する場合も必要です。

## link とは
link は、XCode / Android Studio のプロジェクトに対して、 npm モジュールが、 XCode / AndroidStudio のプロジェクトファイルに対して必要な変更を、 **自動** で代わりに行ってくれるコマンドです。
自動で代わりに行ってくれるだけなので、**手動** で行うこともできます。しかし、たいてい次に記述するように
react-native link コマンドを実行する場合が多いと思うので、よほどのことがなければ、 link コマンドを使った方が良いとおもいます。

## link hoge vs link

// package.json に記載されている module すべてを link する
$ react-native link

// hoge module を link する
$ react-native link hoge

## ファイルの追加について
XCode(iOSアプリ用）の プロジェクトと、 AndroidStudio(Androidアプリ用）の プロジェクトはファイルの管理方法が異なります。

### XCode
- ファイルの場所を、 XCode が管理
- ディレクトリにファイルを追加しただけでは、XCode はそのファイルを認識しません

### XCode補足
- XCodeには、ファイルの管理として、 GroupReference と、FolderReference の２種類あります。 FolderReferenceを作成済みで、その FolderReference にファイルを追加するのであれば、XCode はそのファイルを認識することができます
- ここでいう、XCodeがファイルを認識する、という意味は、ソースコードであれば、 Build の対象になったり、リソースファイルであれば、アプリのバイナリにそのファイルが含まれる対象になるという意味です
- XCodeのProjectファイルツリーと、BuildPhases の内容は、連動しているので、正常にファイルが追加されれば、 Build Phases から確認することができます

### AndroidStudio
- 適切なディレクトリに追加するだけで、AndroidStudio はそのファイルを認識します

## 事例1 フォントの変更
[ReactNative で カスタムフォントを使用する](https://qiita.com/lazyppp/items/4521b26a25459eed9fea)
- ファイルの追加
- XCodeProject ファイルの変更
- Info.plist の変更(iOSアプリ開発で、カスタムフォントを利用するには、Info.plist の変更が必要）

## 事例2 
[react-native-vector-icons](https://github.com/oblador/react-native-vector-icons)

### npm install

```
$npm install react-native-vector-icons --save
+ react-native-vector-icons@4.4.2
updated 1 package in 4.796s

$git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   package-lock.json
	modified:   package.json
```

#### 変更点
 - package.json
 - package-lock.json
 - node_modules (.gitignoreされているので、git status には表示されない）

### link

```
$ react-native link react-native-vector-icons
Scanning folders for symlinks in /Users/hino/Documents/1gn/react/react_native/RNSample/node_modules (17ms)
rnpm-install info Linking react-native-vector-icons android dependency
rnpm-install info Android module react-native-vector-icons has been successfully linked
rnpm-install info Linking react-native-vector-icons ios dependency
rnpm-install info iOS module react-native-vector-icons has been successfully linked
rnpm-install info Linking assets to ios project
rnpm-install WARN ERRGROUP Group 'Resources' does not exist in your Xcode project. We have created it automatically for you.
rnpm-install info Linking assets to android project
rnpm-install info Assets have been successfully linked to your project
$git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   android/app/build.gradle
	modified:   android/app/src/main/java/com/rnsample/MainApplication.java
	modified:   android/settings.gradle
	modified:   ios/RNSample.xcodeproj/project.pbxproj
	modified:   ios/RNSample/Info.plist

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	android/app/src/main/assets/
```

#### XCodeProjectに対する変更
* ios/RNSample.xcodeproj/project.pbxproj
 - node_modules/react-native-vector-icons/Fonts 内のファイルを参照として追加
 - XCodeは上述したとおり、ファイルを参照するという方法なので、module の追加でファイルの追加が必要な場合はこのやり方が自然。
 - ReactNativeIcons のバイナリファイルへの参照を追加
  
* ios/RNSample/Info.plist
このアプリの中で、参照されたフォントを使いますよという宣言が追加されている。

```
+       <key>UIAppFonts</key>
+       <array>
+               <string>Entypo.ttf</string>
+               <string>EvilIcons.ttf</string>
+               <string>Feather.ttf</string>
+               <string>FontAwesome.ttf</string>
+               <string>Foundation.ttf</string>
+               <string>Ionicons.ttf</string>
+               <string>MaterialCommunityIcons.ttf</string>
+               <string>MaterialIcons.ttf</string>
+               <string>Octicons.ttf</string>
+               <string>SimpleLineIcons.ttf</string>
+               <string>Zocial.ttf</string>
+       </array>
```

#### AndroidStudioProject に対する変更
- android/app/build.gradle
アプリのbuild に、:react-native-vector-icons というモジュールを加えますよという宣言

```
+    compile project(':react-native-vector-icons')
```

-  android/app/src/main/java/com/rnsample/MainApplication.java
ReactNative側から、参照するためのソースコード

```
+            new VectorIconsPackage()
```

- settings.gradle

AndroidStudio の Project react-native-vector-icons という AndroidModule を追加するという宣言

```
- +include ':react-native-vector-icons'
+project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
```