diff --git a/packages/phone_log/CHANGELOG.md b/packages/phone_log/CHANGELOG.md
new file mode 100644
index 0000000..2bb0f3c
--- /dev/null
+++ b/packages/phone_log/CHANGELOG.md
@@ -0,0 +1,5 @@
+## [0.0.2] - June 11th, 2018.
+Update README and several fixes.
+
+## [0.0.1] - June 11th, 2018.
+Initial the plugin package.
diff --git a/packages/phone_log/LICENSE b/packages/phone_log/LICENSE
new file mode 100644
index 0000000..8abfae5
--- /dev/null
+++ b/packages/phone_log/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Google Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/phone_log/README.md b/packages/phone_log/README.md
new file mode 100644
index 0000000..c43db9d
--- /dev/null
+++ b/packages/phone_log/README.md
@@ -0,0 +1,41 @@
+# phone_log
+
+A flutter plugin project to access the device phone log (Android only).
+
+Currently only fetching the following 5 fields:
+ CallLog.Calls.CACHED_FORMATTED_NUMBER
+ CallLog.Calls.CACHED_MATCHED_NUMBER
+ CallLog.Calls.TYPE
+ CallLog.Calls.DATE
+ CallLog.Calls.DURATION
+
+For iOS it is not possible to extract the call log programmatically. Apple officially does not expose any public API to access the call log. So all the method will return null on iOS.
+
+## Getting Started
+
+Make sure you add the permission below to your Android Manifest Permission:
+
+```xml
+
+```
+## Usage in Dart
+
+Import the relevant file:
+
+```
+import 'package:phone_log/phone_log.dart';
+```
+
+### Methods
+```dart
+/// Check phone log permission and return a [Future] with the result
+Future checkPermission(Permission permission);
+
+/// Request phone log permission and return a [Future] with the result
+Future requestPermission(Permission permission);
+
+/// Fetch the call log from Android device with a [startDate] and a
+/// minimum [duration]. If startDate == null, all the data will be
+/// fetched out. If duration == null, there will be no duration limit.
+Future> getPhoneLogs();
+```
diff --git a/packages/phone_log/android/build.gradle b/packages/phone_log/android/build.gradle
new file mode 100644
index 0000000..82b011b
--- /dev/null
+++ b/packages/phone_log/android/build.gradle
@@ -0,0 +1,34 @@
+group 'com.jiajiabingcheng.phonelog'
+version '1.0-SNAPSHOT'
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.1'
+ }
+}
+
+rootProject.allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 27
+
+ defaultConfig {
+ minSdkVersion 16
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+}
diff --git a/packages/phone_log/android/gradle.properties b/packages/phone_log/android/gradle.properties
new file mode 100644
index 0000000..8bd86f6
--- /dev/null
+++ b/packages/phone_log/android/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx1536M
diff --git a/packages/phone_log/android/gradle/wrapper/gradle-wrapper.properties b/packages/phone_log/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..eeb2f7e
--- /dev/null
+++ b/packages/phone_log/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Jun 13 15:42:51 PDT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/packages/phone_log/android/settings.gradle b/packages/phone_log/android/settings.gradle
new file mode 100644
index 0000000..633553f
--- /dev/null
+++ b/packages/phone_log/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'phone_log'
diff --git a/packages/phone_log/android/src/main/AndroidManifest.xml b/packages/phone_log/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..dc1cf43
--- /dev/null
+++ b/packages/phone_log/android/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/CallRecord.java b/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/CallRecord.java
new file mode 100644
index 0000000..fba0e48
--- /dev/null
+++ b/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/CallRecord.java
@@ -0,0 +1,35 @@
+package com.jiajiabingcheng.phonelog;
+
+import java.util.HashMap;
+
+class CallRecord {
+
+ CallRecord() {}
+
+ String formattedNumber;
+ String number;
+ String callType;
+ int dateYear;
+ int dateMonth;
+ int dateDay;
+ int dateHour;
+ int dateMinute;
+ int dateSecond;
+ long duration;
+
+ HashMap toMap() {
+ HashMap recordMap = new HashMap<>();
+ recordMap.put("formattedNumber", formattedNumber);
+ recordMap.put("number", number);
+ recordMap.put("callType", callType);
+ recordMap.put("dateYear", dateYear);
+ recordMap.put("dateMonth", dateMonth);
+ recordMap.put("dateDay", dateDay);
+ recordMap.put("dateHour", dateHour);
+ recordMap.put("dateMinute", dateMinute);
+ recordMap.put("dateSecond", dateSecond);
+ recordMap.put("duration", duration);
+
+ return recordMap;
+ }
+}
diff --git a/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/PhoneLogPlugin.java b/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/PhoneLogPlugin.java
new file mode 100644
index 0000000..0b8eccc
--- /dev/null
+++ b/packages/phone_log/android/src/main/java/com/jiajiabingcheng/phonelog/PhoneLogPlugin.java
@@ -0,0 +1,187 @@
+package com.jiajiabingcheng.phonelog;
+
+import android.Manifest;
+import android.annotation.TargetApi;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.os.Build;
+import android.provider.CallLog;
+import android.util.Log;
+
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
+import io.flutter.plugin.common.MethodChannel.Result;
+import io.flutter.plugin.common.PluginRegistry;
+import io.flutter.plugin.common.PluginRegistry.Registrar;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+
+/**
+ * PhoneLogPlugin
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class PhoneLogPlugin implements MethodCallHandler,
+ PluginRegistry.RequestPermissionsResultListener {
+ private final Registrar registrar;
+ private Result pendingResult;
+
+ private PhoneLogPlugin(Registrar registrar) {
+ this.registrar = registrar;
+ }
+
+ public static void registerWith(Registrar registrar) {
+ final MethodChannel channel =
+ new MethodChannel(registrar.messenger(), "github.com/jiajiabingcheng/phone_log");
+ PhoneLogPlugin phoneLogPlugin = new PhoneLogPlugin(registrar);
+ channel.setMethodCallHandler(phoneLogPlugin);
+ registrar.addRequestPermissionsResultListener(phoneLogPlugin);
+ }
+
+ @Override
+ public void onMethodCall(MethodCall call, Result result) {
+ if (pendingResult != null) {
+ pendingResult.error("multiple_requests", "Cancelled by a second request.", null);
+ pendingResult = null;
+ }
+ pendingResult = result;
+ switch (call.method) {
+ case "checkPermission":
+ pendingResult.success(checkPermission());
+ pendingResult = null;
+ break;
+ case "requestPermission":
+ requestPermission();
+ break;
+ case "getPhoneLogs":
+ String startDate = call.argument("startDate");
+ String duration = call.argument("duration");
+ fetchCallRecords(startDate, duration);
+ break;
+ default:
+ result.notImplemented();
+ }
+ }
+
+ private void requestPermission() {
+ Log.i("PhoneLogPlugin", "Requesting permission : " + Manifest.permission.READ_CALL_LOG);
+ String[] perm = {Manifest.permission.READ_CALL_LOG};
+ registrar.activity().requestPermissions(perm, 0);
+ }
+
+ private boolean checkPermission() {
+ Log.i("PhoneLogPlugin", "Checking permission : " + Manifest.permission.READ_CALL_LOG);
+ return PackageManager.PERMISSION_GRANTED
+ == registrar.activity().checkSelfPermission(Manifest.permission.READ_CALL_LOG);
+ }
+
+ @Override
+ public boolean onRequestPermissionsResult(int requestCode,
+ String[] strings,
+ int[] grantResults) {
+ boolean res = false;
+ if (requestCode == 0 && grantResults.length > 0) {
+ res = grantResults[0] == PackageManager.PERMISSION_GRANTED;
+ pendingResult.success(res);
+ pendingResult = null;
+ }
+ return res;
+ }
+
+ private static final String[] PROJECTION =
+ {CallLog.Calls.CACHED_FORMATTED_NUMBER,
+ CallLog.Calls.CACHED_MATCHED_NUMBER,
+ CallLog.Calls.TYPE,
+ CallLog.Calls.DATE,
+ CallLog.Calls.DURATION,};
+
+ @TargetApi(Build.VERSION_CODES.M)
+ private void fetchCallRecords(String startDate, String duration) {
+ if (registrar.activity().checkSelfPermission(Manifest.permission.READ_CALL_LOG)
+ == PackageManager.PERMISSION_GRANTED) {
+ String selectionCondition = null;
+ if (startDate != null) {
+ selectionCondition = CallLog.Calls.DATE + "> " + startDate;
+ }
+ if (duration != null) {
+ String durationSelection = CallLog.Calls.DURATION + "> " + duration;
+ if (selectionCondition != null) {
+ selectionCondition = selectionCondition + " AND " + durationSelection;
+ } else {
+ selectionCondition = durationSelection;
+ }
+ }
+ Cursor cursor = registrar.context().getContentResolver().query(
+ CallLog.Calls.CONTENT_URI, PROJECTION,
+ selectionCondition,
+ null, CallLog.Calls.DATE + " DESC");
+
+ try {
+ ArrayList> records = getCallRecordMaps(cursor);
+ pendingResult.success(records);
+ pendingResult = null;
+ } catch (Exception e) {
+ Log.e("PhoneLog", "Error on fetching call record" + e);
+ pendingResult.error("PhoneLog", e.getMessage(), null);
+ pendingResult = null;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ } else {
+ pendingResult.error("PhoneLog", "Permission is not granted", null);
+ pendingResult = null;
+ }
+ }
+
+
+ /**
+ * Builds the list of call record maps from the cursor
+ *
+ * @param cursor
+ * @return the list of maps
+ */
+ private ArrayList> getCallRecordMaps(Cursor cursor) {
+ ArrayList> records = new ArrayList<>();
+
+ while (cursor != null && cursor.moveToNext()) {
+ CallRecord record = new CallRecord();
+ record.formattedNumber = cursor.getString(0);
+ record.number = cursor.getString(1);
+ record.callType = getCallType(cursor.getInt(2));
+
+ Date date = new Date(cursor.getLong(3));
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ record.dateYear = cal.get(Calendar.YEAR);
+ record.dateMonth = cal.get(Calendar.MONTH);
+ record.dateDay = cal.get(Calendar.DAY_OF_MONTH);
+ record.dateHour = cal.get(Calendar.HOUR_OF_DAY);
+ record.dateMinute = cal.get(Calendar.MINUTE);
+ record.dateSecond = cal.get(Calendar.SECOND);
+ record.duration = cursor.getLong(4);
+
+ records.add(record.toMap());
+ }
+ return records;
+ }
+
+ private String getCallType(int anInt) {
+ switch (anInt) {
+ case CallLog.Calls.INCOMING_TYPE:
+ return "INCOMING_TYPE";
+ case CallLog.Calls.OUTGOING_TYPE:
+ return "OUTGOING_TYPE";
+ case CallLog.Calls.MISSED_TYPE:
+ return "MISSED_TYPE";
+ default:
+ break;
+ }
+ return null;
+ }
+}
diff --git a/packages/phone_log/example/.metadata b/packages/phone_log/example/.metadata
new file mode 100644
index 0000000..8cab361
--- /dev/null
+++ b/packages/phone_log/example/.metadata
@@ -0,0 +1,8 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: 44b7e7d3f42f050a79712daab253af06e9daf530
+ channel: beta
diff --git a/packages/phone_log/example/README.md b/packages/phone_log/example/README.md
new file mode 100644
index 0000000..debe0a3
--- /dev/null
+++ b/packages/phone_log/example/README.md
@@ -0,0 +1,8 @@
+# phone_log_example
+
+Demonstrates how to use the phone_log plugin.
+
+## Getting Started
+
+For help getting started with Flutter, view our online
+[documentation](https://flutter.io/).
diff --git a/packages/phone_log/example/android/app/build.gradle b/packages/phone_log/example/android/app/build.gradle
new file mode 100644
index 0000000..00b0bad
--- /dev/null
+++ b/packages/phone_log/example/android/app/build.gradle
@@ -0,0 +1,51 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+apply plugin: 'com.android.application'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+ compileSdkVersion 27
+
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.example.phonelogexample"
+ minSdkVersion 16
+ targetSdkVersion 27
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+}
diff --git a/packages/phone_log/example/android/app/src/main/AndroidManifest.xml b/packages/phone_log/example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0c2fb2b
--- /dev/null
+++ b/packages/phone_log/example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/phone_log/example/android/app/src/main/java/com/example/phonelogexample/MainActivity.java b/packages/phone_log/example/android/app/src/main/java/com/example/phonelogexample/MainActivity.java
new file mode 100644
index 0000000..1c73ade
--- /dev/null
+++ b/packages/phone_log/example/android/app/src/main/java/com/example/phonelogexample/MainActivity.java
@@ -0,0 +1,14 @@
+package com.example.phonelogexample;
+
+import android.os.Bundle;
+
+import io.flutter.app.FlutterActivity;
+import io.flutter.plugins.GeneratedPluginRegistrant;
+
+public class MainActivity extends FlutterActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ GeneratedPluginRegistrant.registerWith(this);
+ }
+}
diff --git a/packages/phone_log/example/android/app/src/main/res/drawable/launch_background.xml b/packages/phone_log/example/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..5782842
--- /dev/null
+++ b/packages/phone_log/example/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/packages/phone_log/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/phone_log/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/packages/phone_log/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/packages/phone_log/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/phone_log/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/packages/phone_log/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/packages/phone_log/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/phone_log/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/packages/phone_log/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/packages/phone_log/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/phone_log/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/packages/phone_log/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/packages/phone_log/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/phone_log/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/packages/phone_log/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/packages/phone_log/example/android/app/src/main/res/values/styles.xml b/packages/phone_log/example/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..00fa441
--- /dev/null
+++ b/packages/phone_log/example/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/packages/phone_log/example/android/build.gradle b/packages/phone_log/example/android/build.gradle
new file mode 100644
index 0000000..4476887
--- /dev/null
+++ b/packages/phone_log/example/android/build.gradle
@@ -0,0 +1,29 @@
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.1'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/packages/phone_log/example/android/gradle.properties b/packages/phone_log/example/android/gradle.properties
new file mode 100644
index 0000000..8bd86f6
--- /dev/null
+++ b/packages/phone_log/example/android/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-Xmx1536M
diff --git a/packages/phone_log/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/phone_log/example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..aa901e1
--- /dev/null
+++ b/packages/phone_log/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/packages/phone_log/example/android/settings.gradle b/packages/phone_log/example/android/settings.gradle
new file mode 100644
index 0000000..5a2f14f
--- /dev/null
+++ b/packages/phone_log/example/android/settings.gradle
@@ -0,0 +1,15 @@
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+ pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
+}
+
+plugins.each { name, path ->
+ def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+ include ":$name"
+ project(":$name").projectDir = pluginDirectory
+}
diff --git a/packages/phone_log/example/ios/Flutter/AppFrameworkInfo.plist b/packages/phone_log/example/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..6c2de80
--- /dev/null
+++ b/packages/phone_log/example/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ MinimumOSVersion
+ 8.0
+
+
diff --git a/packages/phone_log/example/ios/Flutter/Debug.xcconfig b/packages/phone_log/example/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..e8efba1
--- /dev/null
+++ b/packages/phone_log/example/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/packages/phone_log/example/ios/Flutter/Release.xcconfig b/packages/phone_log/example/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..399e934
--- /dev/null
+++ b/packages/phone_log/example/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/packages/phone_log/example/ios/Runner.xcodeproj/project.pbxproj b/packages/phone_log/example/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..4caa8bc
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,497 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
+ 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 8E7A2CADC98BA27A5BFE6C9A /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E46AD22DB085EB141B1C3 /* libPods-Runner.a */; };
+ 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
+ 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
+ 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
+ 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
+ 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
+ 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
+ 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ A93E46AD22DB085EB141B1C3 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
+ 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
+ 8E7A2CADC98BA27A5BFE6C9A /* libPods-Runner.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
+ 3B80C3931E831B6300D905FE /* App.framework */,
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEBA1CF902C7004384FC /* Flutter.framework */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ B2320E75BCE5DD82766C5A28 /* Pods */,
+ B26DCFF71A1389B9A2E55687 /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
+ 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 97C146F11CF9000F007C117D /* Supporting Files */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+ 97C146F11CF9000F007C117D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146F21CF9000F007C117D /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ B2320E75BCE5DD82766C5A28 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Pods;
+ sourceTree = "";
+ };
+ B26DCFF71A1389B9A2E55687 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ A93E46AD22DB085EB141B1C3 /* libPods-Runner.a */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ D3FAE181685D1E546EE2E398 /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ AF907A40BFCA7C891761DC2B /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0910;
+ ORGANIZATIONNAME = "The Chromium Authors";
+ TargetAttributes = {
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+ AF907A40BFCA7C891761DC2B /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
+ "${PODS_ROOT}/.symlinks/flutter/ios/Flutter.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ D3FAE181685D1E546EE2E398 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
+ 97C146F31CF9000F007C117D /* main.m in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ARCHS = arm64;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = 1;
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.phoneLogExample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ARCHS = arm64;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CURRENT_PROJECT_VERSION = 1;
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.phoneLogExample;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/packages/phone_log/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/phone_log/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..1d526a1
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/packages/phone_log/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/phone_log/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..1263ac8
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/phone_log/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/phone_log/example/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/packages/phone_log/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/phone_log/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/packages/phone_log/example/ios/Runner/AppDelegate.h b/packages/phone_log/example/ios/Runner/AppDelegate.h
new file mode 100644
index 0000000..cf210d2
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/AppDelegate.h
@@ -0,0 +1,6 @@
+#import
+#import
+
+@interface AppDelegate : FlutterAppDelegate
+
+@end
diff --git a/packages/phone_log/example/ios/Runner/AppDelegate.m b/packages/phone_log/example/ios/Runner/AppDelegate.m
new file mode 100644
index 0000000..112becd
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/AppDelegate.m
@@ -0,0 +1,12 @@
+#include "AppDelegate.h"
+#include "GeneratedPluginRegistrant.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ [GeneratedPluginRegistrant registerWithRegistry:self];
+ // Override point for customization after application launch.
+ return [super application:application didFinishLaunchingWithOptions:launchOptions];
+}
+
+@end
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000..3d43d11
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000..28c6bf0
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000..2ccbfd9
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000..f091b6b
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000..4cde121
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000..d0ef06e
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000..dcdc230
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000..2ccbfd9
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000..c8f9ed8
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000..a6d6b86
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000..a6d6b86
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000..75b2d16
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000..c4df70d
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000..6a84f41
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000..d0e1f58
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/packages/phone_log/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/phone_log/example/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/phone_log/example/ios/Runner/Base.lproj/Main.storyboard b/packages/phone_log/example/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/phone_log/example/ios/Runner/Info.plist b/packages/phone_log/example/ios/Runner/Info.plist
new file mode 100644
index 0000000..910bcd8
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ phone_log_example
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/packages/phone_log/example/ios/Runner/main.m b/packages/phone_log/example/ios/Runner/main.m
new file mode 100644
index 0000000..0ccc450
--- /dev/null
+++ b/packages/phone_log/example/ios/Runner/main.m
@@ -0,0 +1,9 @@
+#import
+#import
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/packages/phone_log/example/lib/main.dart b/packages/phone_log/example/lib/main.dart
new file mode 100644
index 0000000..f80cb37
--- /dev/null
+++ b/packages/phone_log/example/lib/main.dart
@@ -0,0 +1,109 @@
+import 'dart:async';
+
+import 'package:fixnum/fixnum.dart';
+import 'package:flutter/material.dart';
+import 'package:phone_log/phone_log.dart';
+
+void main() => runApp(new MyApp());
+
+class MyApp extends StatefulWidget {
+ @override
+ _MyAppState createState() => new _MyAppState();
+}
+
+class _MyAppState extends State {
+ Iterable _callRecords;
+ var phoneLog = new PhoneLog();
+
+ Future fetchCallLogs() async {
+ var callLogs = await phoneLog.getPhoneLogs(
+ // startDate: 20180605, duration: 15 seconds
+ startDate: new Int64(1525590000000),
+ duration: new Int64(13));
+ setState(() {
+ _callRecords = callLogs;
+ });
+ }
+
+
+ requestPermission() async {
+ bool res = await phoneLog.requestPermission();
+ print("permission request result is " + res.toString());
+ }
+
+ checkPermission() async {
+ bool res = await phoneLog.checkPermission();
+ print("permission is " + res.toString());
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ var children = [
+ new Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: new RaisedButton(
+ onPressed: checkPermission, child: new Text("Check permission")),
+ ),
+ new Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: new RaisedButton(
+ onPressed: requestPermission,
+ child: new Text("Request permission")),
+ ),
+ new Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: new RaisedButton(
+ onPressed: fetchCallLogs, child: new Text("Fetch phone log"))),
+ ];
+
+ for (CallRecord call in _callRecords ?? []) {
+ children.addAll([
+ new Container(
+ height: 16.0,
+ ),
+ new Row(
+ children: [
+ new Text(call.formattedNumber ?? call.number ?? 'unknow'),
+ new Padding(
+ child: new Text(call.callType),
+ padding: const EdgeInsets.only(left: 8.0),
+ ),
+ ],
+ crossAxisAlignment: CrossAxisAlignment.center,
+ ),
+ new Row(
+ children: [
+ new Padding(
+ child: new Text(call.dateYear.toString() +
+ '-' +
+ call.dateMonth.toString() +
+ '-' +
+ call.dateDay.toString() +
+ ' ' +
+ call.dateHour.toString() +
+ ': ' +
+ call.dateMinute.toString() +
+ ': ' +
+ call.dateSecond.toString()),
+ padding: const EdgeInsets.only(left: 8.0),
+ ),
+ new Padding(
+ child: new Text(call.duration.toString() + 'seconds'),
+ padding: const EdgeInsets.only(left: 8.0))
+ ],
+ crossAxisAlignment: CrossAxisAlignment.center,
+ )
+ ]);
+ }
+
+ return new MaterialApp(
+ home: new Scaffold(
+ appBar: new AppBar(title: new Text('PhoneLog plugin example')),
+ body: new Center(
+ child: new Column(children: children),
+ ),
+ ),
+ );
+ }
+}
+
diff --git a/packages/phone_log/example/pubspec.yaml b/packages/phone_log/example/pubspec.yaml
new file mode 100644
index 0000000..f890813
--- /dev/null
+++ b/packages/phone_log/example/pubspec.yaml
@@ -0,0 +1,60 @@
+name: phone_log_example
+description: Demonstrates how to use the phone_log plugin.
+
+dependencies:
+ flutter:
+ sdk: flutter
+ fixnum: ^0.10.7
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^0.1.0
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ phone_log:
+ path: ../
+
+# For information on the generic Dart part of this file, see the
+# following page: https://www.dartlang.org/tools/pub/pubspec
+
+# The following section is specific to Flutter.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.io/assets-and-images/#resolution-aware.
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.io/assets-and-images/#from-packages
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.io/custom-fonts/#from-packages
diff --git a/packages/phone_log/ios/Assets/.gitkeep b/packages/phone_log/ios/Assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/phone_log/ios/Classes/PhoneLogPlugin.h b/packages/phone_log/ios/Classes/PhoneLogPlugin.h
new file mode 100644
index 0000000..c253019
--- /dev/null
+++ b/packages/phone_log/ios/Classes/PhoneLogPlugin.h
@@ -0,0 +1,4 @@
+#import
+
+@interface PhoneLogPlugin : NSObject
+@end
diff --git a/packages/phone_log/ios/Classes/PhoneLogPlugin.m b/packages/phone_log/ios/Classes/PhoneLogPlugin.m
new file mode 100644
index 0000000..16fd6df
--- /dev/null
+++ b/packages/phone_log/ios/Classes/PhoneLogPlugin.m
@@ -0,0 +1,22 @@
+#import "PhoneLogPlugin.h"
+
+@implementation PhoneLogPlugin
++ (void)registerWithRegistrar:(NSObject*)registrar {
+ FlutterMethodChannel* channel = [FlutterMethodChannel
+ methodChannelWithName:@"github.com/jiajiabingcheng/phone_log"
+ binaryMessenger:[registrar messenger]];
+ PhoneLogPlugin* instance = [[PhoneLogPlugin alloc] init];
+ [registrar addMethodCallDelegate:instance channel:channel];
+}
+
+- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
+ if ([@"checkPermission" isEqualToString:call.method] ||
+ [@"requestPermission" isEqualToString:call.method] ||
+ [@"getPhoneLogs" isEqualToString:call.method]) {
+ result(nil);
+ } else {
+ result(FlutterMethodNotImplemented);
+ }
+}
+
+@end
diff --git a/packages/phone_log/ios/phone_log.podspec b/packages/phone_log/ios/phone_log.podspec
new file mode 100644
index 0000000..31587fc
--- /dev/null
+++ b/packages/phone_log/ios/phone_log.podspec
@@ -0,0 +1,21 @@
+#
+# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
+#
+Pod::Spec.new do |s|
+ s.name = 'phone_log'
+ s.version = '0.0.1'
+ s.summary = 'A new flutter plugin project.'
+ s.description = <<-DESC
+A new flutter plugin project.
+ DESC
+ s.homepage = 'http://example.com'
+ s.license = { :file => '../LICENSE' }
+ s.author = { 'Your Company' => 'email@example.com' }
+ s.source = { :path => '.' }
+ s.source_files = 'Classes/**/*'
+ s.public_header_files = 'Classes/**/*.h'
+ s.dependency 'Flutter'
+
+ s.ios.deployment_target = '8.0'
+end
+
diff --git a/packages/phone_log/lib/phone_log.dart b/packages/phone_log/lib/phone_log.dart
new file mode 100644
index 0000000..f678709
--- /dev/null
+++ b/packages/phone_log/lib/phone_log.dart
@@ -0,0 +1,76 @@
+import 'dart:async';
+
+import 'package:fixnum/fixnum.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+
+/// Provide methods to access and fetch the phone log.
+class PhoneLog {
+ final MethodChannel _channel;
+
+ static final PhoneLog _instance = new PhoneLog.private(
+ const MethodChannel('github.com/jiajiabingcheng/phone_log'));
+
+ /// Provides an instance of this class.
+ factory PhoneLog() => _instance;
+
+ @visibleForTesting
+ PhoneLog.private(MethodChannel platformChannel):_channel = platformChannel;
+
+ /// Check a [permission] and return a [Future] with the result
+ Future checkPermission() async {
+ final bool isGranted = await _channel.invokeMethod("checkPermission", null);
+ return isGranted;
+ }
+
+ /// Request a [permission] and return a [Future] with the result
+ Future requestPermission() async {
+ final bool isGranted =
+ await _channel.invokeMethod("requestPermission", null);
+ return isGranted;
+ }
+
+ ///Fetches phone logs
+ ///
+ ///The unit of [startDate] is the Milliseconds of date.
+ ///The unit of [duration] is second.
+ Future> getPhoneLogs(
+ {Int64 startDate, Int64 duration}) async {
+ var _startDate = startDate?.toString();
+ var _duration = duration?.toString();
+ Iterable records = await _channel.invokeMethod(
+ 'getPhoneLogs', {"startDate": _startDate, "duration": _duration});
+ return records?.map((m) => new CallRecord.fromMap(m));
+ }
+}
+
+/// The class that carries all the data for one call history entry.
+class CallRecord {
+ CallRecord({
+ this.formattedNumber,
+ this.number,
+ this.callType,
+ this.dateYear,
+ this.dateMonth,
+ this.dateHour,
+ this.dateMinute,
+ this.dateSecond,
+ this.duration,
+ });
+
+ String formattedNumber, number, callType;
+ int dateYear, dateMonth, dateDay, dateHour, dateMinute, dateSecond, duration;
+
+ CallRecord.fromMap(Map m) {
+ formattedNumber = m['formattedNumber'];
+ number = m['number'];
+ callType = m['callType'];
+ dateYear = m['dateYear'];
+ dateMonth = m['dateMonth'];
+ dateDay = m['dateDay'];
+ dateHour = m['dateHour'];
+ dateMinute = m['dateMinute'];
+ dateSecond = m['dateSecond'];
+ duration = m['duration'];
+ }
+}
diff --git a/packages/phone_log/pubspec.yaml b/packages/phone_log/pubspec.yaml
new file mode 100644
index 0000000..e8fe5e3
--- /dev/null
+++ b/packages/phone_log/pubspec.yaml
@@ -0,0 +1,24 @@
+name: phone_log
+description: A new flutter plugin project.
+version: 0.0.2
+author: Jiaming Cheng
+homepage: https://github.com/jiajiabingcheng/phone_log
+
+environment:
+ sdk: ">=1.19.0 <2.0.0"
+
+dependencies:
+ flutter:
+ sdk: flutter
+ fixnum: ^0.10.7
+
+# The following section is specific to Flutter.
+flutter:
+ plugin:
+ androidPackage: com.jiajiabingcheng.phonelog
+ pluginClass: PhoneLogPlugin
+
+dev_dependencies:
+ mockito: ^2.0.2
+ flutter_test:
+ sdk: flutter
diff --git a/packages/phone_log/test/phone_log_test.dart b/packages/phone_log/test/phone_log_test.dart
new file mode 100644
index 0000000..60fc5cd
--- /dev/null
+++ b/packages/phone_log/test/phone_log_test.dart
@@ -0,0 +1,86 @@
+import 'dart:async';
+
+import 'package:fixnum/fixnum.dart';
+import 'package:flutter/services.dart';
+import 'package:mockito/mockito.dart';
+import 'package:test/test.dart';
+
+import 'package:phone_log/phone_log.dart';
+
+void main() {
+ String invokedMethod;
+ dynamic arguments;
+ MockPlatformChannel mockChannel;
+ MockPlatformChannel mockChannelForGetLogs;
+
+ setUp(() {
+ mockChannel = new MockPlatformChannel();
+ mockChannelForGetLogs = new MockPlatformChannel();
+
+ when(mockChannel.invokeMethod(typed(any), any))
+ .thenAnswer((Invocation invocation) {
+ invokedMethod = invocation.positionalArguments[0];
+ arguments = invocation.positionalArguments[1];
+ });
+
+ when(mockChannelForGetLogs.invokeMethod('getPhoneLogs', any))
+ .thenReturn(new Future(() => [
+ {
+ 'formattedNumber': '123 123 1234',
+ 'number': '1231231234',
+ 'callType': 'INCOMING_TYPE',
+ 'dateYear': 2018,
+ 'dateMonth': 6,
+ 'dateDay': 15,
+ 'dateHour': 3,
+ 'dateMinute': 16,
+ 'dateSecond': 23,
+ 'duration': 123
+ }
+ ]));
+ });
+
+ group('Phone log plugin', () {
+ test('fetch phone log', () async {
+ var phoneLog = new PhoneLog.private(mockChannelForGetLogs);
+
+ var records = await phoneLog.getPhoneLogs(
+ startDate: new Int64(123456789), duration: new Int64(12));
+
+ print(records);
+ var record = records.first;
+
+ expect(record.formattedNumber, '123 123 1234');
+ expect(record.callType, 'INCOMING_TYPE');
+ expect(record.number, '1231231234');
+ expect(record.dateYear, 2018);
+ expect(record.duration, 123);
+
+ var phoneLogMethod = new PhoneLog.private(mockChannel);
+ await phoneLogMethod.getPhoneLogs(
+ startDate: new Int64(123456789), duration: new Int64(12));
+ expect(invokedMethod, 'getPhoneLogs');
+ expect(arguments, {'startDate': '123456789', 'duration': '12'});
+ });
+
+ test('check permission', () async {
+ var phoneLog = new PhoneLog.private(mockChannel);
+
+ await phoneLog.checkPermission();
+
+ expect(invokedMethod, 'checkPermission');
+ expect(arguments, null);
+ });
+
+ test('request permission', () async {
+ var phoneLog = new PhoneLog.private(mockChannel);
+
+ await phoneLog.requestPermission();
+
+ expect(invokedMethod, 'requestPermission');
+ expect(arguments, null);
+ });
+ });
+}
+
+class MockPlatformChannel extends Mock implements MethodChannel {}