[path_provider] add getApplicationLibraryDirectory (#1953)

* [path_provider] add getLibraryDirectory
diff --git a/.gitignore b/.gitignore
index ccb0eeb..7341696 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
 ServiceDefinitions.json
 xcuserdata/
 *.xcworkspace
+**/DerivedData/
 
 local.properties
 keystore.properties
diff --git a/packages/path_provider/CHANGELOG.md b/packages/path_provider/CHANGELOG.md
index 498127a..6ded477 100644
--- a/packages/path_provider/CHANGELOG.md
+++ b/packages/path_provider/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 1.3.0
+
+* Added iOS-only support for `getLibraryDirectory`.
+* Update integration tests and example test.
+* Update example app UI to use a `ListView` show the list of content.
+* Update .gitignore to include Xcode build output folder `**/DerivedData/`
+
 ## 1.2.2
 
 * Correct the integration test for Android's `getApplicationSupportDirectory` call.
diff --git a/packages/path_provider/example/lib/main.dart b/packages/path_provider/example/lib/main.dart
index bea99bc..2e9e951 100644
--- a/packages/path_provider/example/lib/main.dart
+++ b/packages/path_provider/example/lib/main.dart
@@ -36,6 +36,7 @@
 class _MyHomePageState extends State<MyHomePage> {
   Future<Directory> _tempDirectory;
   Future<Directory> _appSupportDirectory;
+  Future<Directory> _appLibraryDirectory;
   Future<Directory> _appDocumentsDirectory;
   Future<Directory> _externalDocumentsDirectory;
 
@@ -72,6 +73,12 @@
     });
   }
 
+  void _requestAppLibraryDirectory() {
+    setState(() {
+      _appLibraryDirectory = getLibraryDirectory();
+    });
+  }
+
   void _requestExternalStorageDirectory() {
     setState(() {
       _externalDocumentsDirectory = getExternalStorageDirectory();
@@ -85,70 +92,55 @@
         title: Text(widget.title),
       ),
       body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+        child: ListView(
           children: <Widget>[
-            Column(
-              children: <Widget>[
-                Padding(
-                  padding: const EdgeInsets.all(16.0),
-                  child: RaisedButton(
-                    child: const Text('Get Temporary Directory'),
-                    onPressed: _requestTempDirectory,
-                  ),
-                ),
-              ],
-            ),
-            Expanded(
-              child: FutureBuilder<Directory>(
-                  future: _tempDirectory, builder: _buildDirectory),
-            ),
-            Column(
-              children: <Widget>[
-                Padding(
-                  padding: const EdgeInsets.all(16.0),
-                  child: RaisedButton(
-                    child: const Text('Get Application Documents Directory'),
-                    onPressed: _requestAppDocumentsDirectory,
-                  ),
-                ),
-              ],
-            ),
-            Expanded(
-              child: FutureBuilder<Directory>(
-                  future: _appDocumentsDirectory, builder: _buildDirectory),
-            ),
-            Column(
-              children: <Widget>[
-                Padding(
-                  padding: const EdgeInsets.all(16.0),
-                  child: RaisedButton(
-                    child: const Text('Get Application Support Directory'),
-                    onPressed: _requestAppSupportDirectory,
-                  ),
-                ),
-              ],
-            ),
-            Expanded(
-              child: FutureBuilder<Directory>(
-                  future: _appSupportDirectory, builder: _buildDirectory),
-            ),
-            Column(children: <Widget>[
-              Padding(
-                padding: const EdgeInsets.all(16.0),
-                child: RaisedButton(
-                  child: Text(
-                      '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'),
-                  onPressed:
-                      Platform.isIOS ? null : _requestExternalStorageDirectory,
-                ),
+            Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: RaisedButton(
+                child: const Text('Get Temporary Directory'),
+                onPressed: _requestTempDirectory,
               ),
-            ]),
-            Expanded(
-              child: FutureBuilder<Directory>(
-                  future: _externalDocumentsDirectory,
-                  builder: _buildDirectory),
             ),
+            FutureBuilder<Directory>(
+                future: _tempDirectory, builder: _buildDirectory),
+            Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: RaisedButton(
+                child: const Text('Get Application Documents Directory'),
+                onPressed: _requestAppDocumentsDirectory,
+              ),
+            ),
+            FutureBuilder<Directory>(
+                future: _appDocumentsDirectory, builder: _buildDirectory),
+            Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: RaisedButton(
+                child: const Text('Get Application Support Directory'),
+                onPressed: _requestAppSupportDirectory,
+              ),
+            ),
+            FutureBuilder<Directory>(
+                future: _appSupportDirectory, builder: _buildDirectory),
+            Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: RaisedButton(
+                child: const Text('Get Application Library Directory'),
+                onPressed: _requestAppLibraryDirectory,
+              ),
+            ),
+            FutureBuilder<Directory>(
+                future: _appLibraryDirectory, builder: _buildDirectory),
+            Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: RaisedButton(
+                child: Text(
+                    '${Platform.isIOS ? "External directories are unavailable " "on iOS" : "Get External Storage Directory"}'),
+                onPressed:
+                    Platform.isIOS ? null : _requestExternalStorageDirectory,
+              ),
+            ),
+            FutureBuilder<Directory>(
+                future: _externalDocumentsDirectory, builder: _buildDirectory)
           ],
         ),
       ),
diff --git a/packages/path_provider/example/test_driver/path_provider.dart b/packages/path_provider/example/test_driver/path_provider.dart
index ca9ae8c..8438965 100644
--- a/packages/path_provider/example/test_driver/path_provider.dart
+++ b/packages/path_provider/example/test_driver/path_provider.dart
@@ -45,6 +45,21 @@
     file.deleteSync();
   });
 
+  test('getLibraryDirectory', () async {
+    if (Platform.isIOS) {
+      final Directory result = await getLibraryDirectory();
+      final String uuid = Uuid().v1();
+      final File file = File('${result.path}/$uuid.txt');
+      file.writeAsStringSync('Hello world!');
+      expect(file.readAsStringSync(), 'Hello world!');
+      expect(result.listSync(), isNotEmpty);
+      file.deleteSync();
+    } else if (Platform.isAndroid) {
+      final Future<Directory> result = getLibraryDirectory();
+      expect(result, throwsA(isInstanceOf<UnsupportedError>()));
+    }
+  });
+
   test('getExternalStorageDirectory', () async {
     if (Platform.isIOS) {
       final Future<Directory> result = getExternalStorageDirectory();
diff --git a/packages/path_provider/ios/Classes/PathProviderPlugin.m b/packages/path_provider/ios/Classes/PathProviderPlugin.m
index a8dc4a7..1bf0e7a 100644
--- a/packages/path_provider/ios/Classes/PathProviderPlugin.m
+++ b/packages/path_provider/ios/Classes/PathProviderPlugin.m
@@ -42,6 +42,8 @@
       } else {
         result(path);
       }
+    } else if ([@"getLibraryDirectory" isEqualToString:call.method]) {
+      result([self getLibraryDirectory]);
     } else {
       result(FlutterMethodNotImplemented);
     }
@@ -60,4 +62,8 @@
   return GetDirectoryOfType(NSApplicationSupportDirectory);
 }
 
++ (NSString*)getLibraryDirectory {
+  return GetDirectoryOfType(NSLibraryDirectory);
+}
+
 @end
diff --git a/packages/path_provider/lib/path_provider.dart b/packages/path_provider/lib/path_provider.dart
index 069973a..f058722 100644
--- a/packages/path_provider/lib/path_provider.dart
+++ b/packages/path_provider/lib/path_provider.dart
@@ -59,6 +59,17 @@
   return Directory(path);
 }
 
+/// Path to the directory where application can store files that are persistent,
+/// backed up, and not visible to the user, such as sqlite.db.
+Future<Directory> getLibraryDirectory() async {
+  final String path =
+      await _channel.invokeMethod<String>('getLibraryDirectory');
+  if (path == null) {
+    return null;
+  }
+  return Directory(path);
+}
+
 /// Path to a directory where the application may place data that is
 /// user-generated, or that cannot otherwise be recreated by your application.
 ///
diff --git a/packages/path_provider/pubspec.yaml b/packages/path_provider/pubspec.yaml
index e7e7555..80c6bde 100644
--- a/packages/path_provider/pubspec.yaml
+++ b/packages/path_provider/pubspec.yaml
@@ -3,7 +3,7 @@
   iOS file systems, such as the temp and app data directories.
 author: Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider
-version: 1.2.2
+version: 1.3.0
 
 flutter:
   plugin:
diff --git a/packages/path_provider/test/path_provider_test.dart b/packages/path_provider/test/path_provider_test.dart
index 1e8afec..24368c0 100644
--- a/packages/path_provider/test/path_provider_test.dart
+++ b/packages/path_provider/test/path_provider_test.dart
@@ -64,6 +64,18 @@
     expect(directory, isNull);
   });
 
+  test('getApplicationSupportDirectory test', () async {
+    response = null;
+    final Directory directory = await getApplicationSupportDirectory();
+    expect(
+      log,
+      <Matcher>[
+        isMethodCall('getApplicationSupportDirectory', arguments: null)
+      ],
+    );
+    expect(directory, isNull);
+  });
+
   test('getExternalStorageDirectory test', () async {
     response = null;
     final Directory directory = await getExternalStorageDirectory();
@@ -74,6 +86,16 @@
     expect(directory, isNull);
   });
 
+  test('getLibraryDirectory test', () async {
+    response = null;
+    final Directory directory = await getLibraryDirectory();
+    expect(
+      log,
+      <Matcher>[isMethodCall('getLibraryDirectory', arguments: null)],
+    );
+    expect(directory, isNull);
+  });
+
   test('getExternalStorageDirectory iOS test', () async {
     setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios'));
 
@@ -107,6 +129,20 @@
     expect(directory.path, equals(fakePath));
   });
 
+  test('ApplicationSupportDirectory path test', () async {
+    final String fakePath = "/foo/bar/baz";
+    response = fakePath;
+    final Directory directory = await getApplicationSupportDirectory();
+    expect(directory.path, equals(fakePath));
+  });
+
+  test('ApplicationLibraryDirectory path test', () async {
+    final String fakePath = "/foo/bar/baz";
+    response = fakePath;
+    final Directory directory = await getLibraryDirectory();
+    expect(directory.path, equals(fakePath));
+  });
+
   test('ExternalStorageDirectory path test', () async {
     final String fakePath = "/foo/bar/baz";
     response = fakePath;