Added iOS example for add-to-app Pigeon (#722)

pull/754/head
gaaclarke 4 years ago committed by GitHub
parent eab215f1b7
commit 5adf66ba65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -18,13 +18,15 @@ page.
* On Android, the Kotlin app already uses GSON and OkHttp for networking and * On Android, the Kotlin app already uses GSON and OkHttp for networking and
references the Google Books API as a data source. These same libraries also references the Google Books API as a data source. These same libraries also
underpin the data fetched and shown in the Flutter screen. underpin the data fetched and shown in the Flutter screen.
* iOS TODO. * On iOS, the Swift app does a similar fetch and parse of the Google Books API
using iOS's built-in libraries.
* The platform application interfaces with the Flutter book details page using * The platform application interfaces with the Flutter book details page using
idiomatic platform API conventions rather than Flutter conventions. idiomatic platform API conventions rather than Flutter conventions.
* On Android, the Flutter activity receives the book to show via activity * On Android, the Flutter activity receives the book to show via activity
intent and returns the edited book by setting the result intent on the intent and returns the edited book by setting the result intent on the
activity. No Flutter concepts are leaked into the consumer activity. activity. No Flutter concepts are leaked into the consumer activity.
* iOS TODO. * On iOS, Storyboards are used to design the presentation of the books, just
as one might do in a full UIKit app.
* The [pigeon](https://pub.dev/packages/pigeon) plugin is used to generate * The [pigeon](https://pub.dev/packages/pigeon) plugin is used to generate
interop APIs and data classes. The same `Book` model class is used within the interop APIs and data classes. The same `Book` model class is used within the
Kotlin/Swift program, the Dart program and in the interop between Kotlin/Swift Kotlin/Swift program, the Dart program and in the interop between Kotlin/Swift
@ -36,10 +38,13 @@ page.
* If the `schema.dart` is modified, the generated classes can be updated with * If the `schema.dart` is modified, the generated classes can be updated with
```bash ```bash
flutter pub run pigeon \ flutter pub run pigeon --input pigeon/schema.dart \
--input pigeon/schema.dart \ --dart_out lib/api.dart \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \ --objc_header_out ../ios_books/IosBooks/api.h \
--java_package "dev.flutter.example.books" --objc_source_out ../ios_books/IosBooks/api.m \
--objc_prefix BK \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"
``` ```
in the `flutter_module_books` directory. in the `flutter_module_books` directory.
@ -66,13 +71,16 @@ you're building for both iOS and Android, with both toolchains installed):
# Or open the ../android_books folder in Android Studio for other platforms. # Or open the ../android_books folder in Android Studio for other platforms.
# For iOS builds: # For iOS builds:
# TODO iOS sample cd ../ios_books
pod install
open ios_books/IosBooks.xcworkspace
``` ```
## Requirements ## Requirements
* Flutter * Flutter
* Android Studio * Android Studio
* Cocoapods (iOS)
## Questions/issues ## Questions/issues

@ -1,15 +1,16 @@
// Autogenerated from Pigeon (v0.1.0), do not edit directly. // Autogenerated from Pigeon (v0.1.17), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
package dev.flutter.example.books; package dev.flutter.example.books;
import java.util.HashMap;
import io.flutter.plugin.common.BasicMessageChannel; import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec; import io.flutter.plugin.common.StandardMessageCodec;
import java.util.ArrayList;
import java.util.HashMap;
/** Generated class from Pigeon. */ /** Generated class from Pigeon. */
@SuppressWarnings("unused")
public class Api { public class Api {
/** Generated class from Pigeon that represents data sent in messages. */ /** Generated class from Pigeon that represents data sent in messages. */
@ -26,9 +27,9 @@ public class Api {
public String getAuthor() { return author; } public String getAuthor() { return author; }
public void setAuthor(String setterArg) { this.author = setterArg; } public void setAuthor(String setterArg) { this.author = setterArg; }
private String description; private String summary;
public String getDescription() { return description; } public String getSummary() { return summary; }
public void setDescription(String setterArg) { this.description = setterArg; } public void setSummary(String setterArg) { this.summary = setterArg; }
private String publishDate; private String publishDate;
public String getPublishDate() { return publishDate; } public String getPublishDate() { return publishDate; }
@ -39,30 +40,36 @@ public class Api {
public void setPageCount(Long setterArg) { this.pageCount = setterArg; } public void setPageCount(Long setterArg) { this.pageCount = setterArg; }
HashMap toMap() { HashMap toMap() {
HashMap<String, Object> toMapResult = new HashMap<String, Object>(); HashMap<String, Object> toMapResult = new HashMap<>();
toMapResult.put("title", title); toMapResult.put("title", title);
toMapResult.put("subtitle", subtitle); toMapResult.put("subtitle", subtitle);
toMapResult.put("author", author); toMapResult.put("author", author);
toMapResult.put("description", description); toMapResult.put("summary", summary);
toMapResult.put("publishDate", publishDate); toMapResult.put("publishDate", publishDate);
toMapResult.put("pageCount", pageCount); toMapResult.put("pageCount", pageCount);
return toMapResult; return toMapResult;
} }
static Book fromMap(HashMap map) { static Book fromMap(HashMap map) {
Book fromMapResult = new Book(); Book fromMapResult = new Book();
fromMapResult.title = (String)map.get("title"); Object title = map.get("title");
fromMapResult.subtitle = (String)map.get("subtitle"); fromMapResult.title = (String)title;
fromMapResult.author = (String)map.get("author"); Object subtitle = map.get("subtitle");
fromMapResult.description = (String)map.get("description"); fromMapResult.subtitle = (String)subtitle;
fromMapResult.publishDate = (String)map.get("publishDate"); Object author = map.get("author");
fromMapResult.pageCount = (map.get("pageCount") instanceof Integer) ? (Integer)map.get("pageCount") : (Long)map.get("pageCount"); fromMapResult.author = (String)author;
Object summary = map.get("summary");
fromMapResult.summary = (String)summary;
Object publishDate = map.get("publishDate");
fromMapResult.publishDate = (String)publishDate;
Object pageCount = map.get("pageCount");
fromMapResult.pageCount = (pageCount == null) ? null : ((pageCount instanceof Integer) ? (Integer)pageCount : (Long)pageCount);
return fromMapResult; return fromMapResult;
} }
} }
/** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/ /** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/
public static class FlutterBookApi { public static class FlutterBookApi {
private BinaryMessenger binaryMessenger; private final BinaryMessenger binaryMessenger;
public FlutterBookApi(BinaryMessenger argBinaryMessenger){ public FlutterBookApi(BinaryMessenger argBinaryMessenger){
this.binaryMessenger = argBinaryMessenger; this.binaryMessenger = argBinaryMessenger;
} }
@ -71,12 +78,10 @@ public class Api {
} }
public void displayBookDetails(Book argInput, Reply<Void> callback) { public void displayBookDetails(Book argInput, Reply<Void> callback) {
BasicMessageChannel<Object> channel = BasicMessageChannel<Object> channel =
new BasicMessageChannel<Object>(binaryMessenger, "dev.flutter.pigeon.FlutterBookApi.displayBookDetails", new StandardMessageCodec()); new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.FlutterBookApi.displayBookDetails", new StandardMessageCodec());
HashMap inputMap = argInput.toMap(); HashMap inputMap = argInput.toMap();
channel.send(inputMap, new BasicMessageChannel.Reply<Object>() { channel.send(inputMap, channelReply -> {
public void reply(Object channelReply) { callback.reply(null);
callback.reply(null);
}
}); });
} }
} }
@ -90,20 +95,18 @@ public class Api {
static void setup(BinaryMessenger binaryMessenger, HostBookApi api) { static void setup(BinaryMessenger binaryMessenger, HostBookApi api) {
{ {
BasicMessageChannel<Object> channel = BasicMessageChannel<Object> channel =
new BasicMessageChannel<Object>(binaryMessenger, "dev.flutter.pigeon.HostBookApi.cancel", new StandardMessageCodec()); new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.HostBookApi.cancel", new StandardMessageCodec());
if (api != null) { if (api != null) {
channel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() { channel.setMessageHandler((message, reply) -> {
public void onMessage(Object message, BasicMessageChannel.Reply<Object> reply) { HashMap<String, HashMap> wrapped = new HashMap<>();
HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>(); try {
try { api.cancel();
api.cancel(); wrapped.put("result", null);
wrapped.put("result", null); }
} catch (Exception exception) {
catch (Exception exception) { wrapped.put("error", wrapError(exception));
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
} }
reply.reply(wrapped);
}); });
} else { } else {
channel.setMessageHandler(null); channel.setMessageHandler(null);
@ -111,21 +114,20 @@ public class Api {
} }
{ {
BasicMessageChannel<Object> channel = BasicMessageChannel<Object> channel =
new BasicMessageChannel<Object>(binaryMessenger, "dev.flutter.pigeon.HostBookApi.finishEditingBook", new StandardMessageCodec()); new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.HostBookApi.finishEditingBook", new StandardMessageCodec());
if (api != null) { if (api != null) {
channel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() { channel.setMessageHandler((message, reply) -> {
public void onMessage(Object message, BasicMessageChannel.Reply<Object> reply) { HashMap<String, HashMap> wrapped = new HashMap<>();
try {
@SuppressWarnings("ConstantConditions")
Book input = Book.fromMap((HashMap)message); Book input = Book.fromMap((HashMap)message);
HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>(); api.finishEditingBook(input);
try { wrapped.put("result", null);
api.finishEditingBook(input); }
wrapped.put("result", null); catch (Exception exception) {
} wrapped.put("error", wrapError(exception));
catch (Exception exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
} }
reply.reply(wrapped);
}); });
} else { } else {
channel.setMessageHandler(null); channel.setMessageHandler(null);
@ -134,9 +136,9 @@ public class Api {
} }
} }
private static HashMap wrapError(Exception exception) { private static HashMap wrapError(Exception exception) {
HashMap<String, Object> errorMap = new HashMap<String, Object>(); HashMap<String, Object> errorMap = new HashMap<>();
errorMap.put("message", exception.toString()); errorMap.put("message", exception.toString());
errorMap.put("code", null); errorMap.put("code", exception.getClass().getSimpleName());
errorMap.put("details", null); errorMap.put("details", null);
return errorMap; return errorMap;
} }

@ -91,7 +91,7 @@ class MainActivity : AppCompatActivity() {
book.subtitle = volumeInfoJson.get("subtitle")?.asString book.subtitle = volumeInfoJson.get("subtitle")?.asString
// Sorry co-authors, we're trying to keep this simple. // Sorry co-authors, we're trying to keep this simple.
book.author = volumeInfoJson.getAsJsonArray("authors")[0].asString book.author = volumeInfoJson.getAsJsonArray("authors")[0].asString
book.description = volumeInfoJson.get("description").asString book.summary = volumeInfoJson.get("description").asString
book.publishDate = volumeInfoJson.get("publishedDate").asString book.publishDate = volumeInfoJson.get("publishedDate").asString
book.pageCount = volumeInfoJson.get("pageCount").asLong book.pageCount = volumeInfoJson.get("pageCount").asLong
books.add(book) books.add(book)

@ -16,10 +16,13 @@ in `pigeon/schema.dart` is updated, the generated classes can also be re-
generated using: generated using:
```shell ```shell
flutter pub run pigeon \ flutter pub run pigeon --input pigeon/schema.dart \
--input pigeon/schema.dart \ --dart_out lib/api.dart \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \ --objc_header_out ../ios_books/IosBooks/api.h \
--java_package "dev.flutter.example.books" --objc_source_out ../ios_books/IosBooks/api.m \
--objc_prefix BK \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"
``` ```
## Demonstrated concepts ## Demonstrated concepts

@ -1,38 +1,42 @@
// Autogenerated from Pigeon (v0.1.0), do not edit directly. // Autogenerated from Pigeon (v0.1.17), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class Book { class Book {
String title; String title;
String subtitle; String subtitle;
String author; String author;
String description; String summary;
String publishDate; String publishDate;
int pageCount; int pageCount;
// ignore: unused_element // ignore: unused_element
Map<dynamic, dynamic> _toMap() { Object encode() {
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{}; final Map<Object, Object> pigeonMap = <Object, Object>{};
pigeonMap['title'] = title; pigeonMap['title'] = title;
pigeonMap['subtitle'] = subtitle; pigeonMap['subtitle'] = subtitle;
pigeonMap['author'] = author; pigeonMap['author'] = author;
pigeonMap['description'] = description; pigeonMap['summary'] = summary;
pigeonMap['publishDate'] = publishDate; pigeonMap['publishDate'] = publishDate;
pigeonMap['pageCount'] = pageCount; pigeonMap['pageCount'] = pageCount;
return pigeonMap; return pigeonMap;
} }
// ignore: unused_element // ignore: unused_element
static Book _fromMap(Map<dynamic, dynamic> pigeonMap) { static Book decode(Object message) {
final Book result = Book(); final Map<Object, Object> pigeonMap = message as Map<Object, Object>;
result.title = pigeonMap['title']; return Book()
result.subtitle = pigeonMap['subtitle']; ..title = pigeonMap['title'] as String
result.author = pigeonMap['author']; ..subtitle = pigeonMap['subtitle'] as String
result.description = pigeonMap['description']; ..author = pigeonMap['author'] as String
result.publishDate = pigeonMap['publishDate']; ..summary = pigeonMap['summary'] as String
result.pageCount = pigeonMap['pageCount']; ..publishDate = pigeonMap['publishDate'] as String
return result; ..pageCount = pigeonMap['pageCount'] as int;
} }
} }
@ -40,59 +44,71 @@ abstract class FlutterBookApi {
void displayBookDetails(Book arg); void displayBookDetails(Book arg);
static void setup(FlutterBookApi api) { static void setup(FlutterBookApi api) {
{ {
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>( const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.FlutterBookApi.displayBookDetails', 'dev.flutter.pigeon.FlutterBookApi.displayBookDetails',
StandardMessageCodec()); StandardMessageCodec());
channel.setMessageHandler((dynamic message) async { if (api == null) {
final Map<dynamic, dynamic> mapMessage = channel.setMessageHandler(null);
message as Map<dynamic, dynamic>; } else {
final Book input = Book._fromMap(mapMessage); channel.setMessageHandler((Object message) async {
api.displayBookDetails(input); if (message == null) {
}); return;
}
final Book input = Book.decode(message);
api.displayBookDetails(input);
return;
});
}
} }
} }
} }
class HostBookApi { class HostBookApi {
Future<void> cancel() async { Future<void> cancel() async {
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>( const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.HostBookApi.cancel', StandardMessageCodec()); 'dev.flutter.pigeon.HostBookApi.cancel', StandardMessageCodec());
final Map<Object, Object> replyMap =
final Map<dynamic, dynamic> replyMap = await channel.send(null); await channel.send(null) as Map<Object, Object>;
if (replyMap == null) { if (replyMap == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
message: 'Unable to establish connection on channel.', message: 'Unable to establish connection on channel.',
details: null); details: null,
);
} else if (replyMap['error'] != null) { } else if (replyMap['error'] != null) {
final Map<dynamic, dynamic> error = replyMap['error']; final Map<Object, Object> error =
replyMap['error'] as Map<Object, Object>;
throw PlatformException( throw PlatformException(
code: error['code'], code: error['code'] as String,
message: error['message'], message: error['message'] as String,
details: error['details']); details: error['details'],
);
} else { } else {
// noop // noop
} }
} }
Future<void> finishEditingBook(Book arg) async { Future<void> finishEditingBook(Book arg) async {
final Map<dynamic, dynamic> requestMap = arg._toMap(); final Object encoded = arg.encode();
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>( const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.HostBookApi.finishEditingBook', 'dev.flutter.pigeon.HostBookApi.finishEditingBook',
StandardMessageCodec()); StandardMessageCodec());
final Map<Object, Object> replyMap =
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap); await channel.send(encoded) as Map<Object, Object>;
if (replyMap == null) { if (replyMap == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
message: 'Unable to establish connection on channel.', message: 'Unable to establish connection on channel.',
details: null); details: null,
);
} else if (replyMap['error'] != null) { } else if (replyMap['error'] != null) {
final Map<dynamic, dynamic> error = replyMap['error']; final Map<Object, Object> error =
replyMap['error'] as Map<Object, Object>;
throw PlatformException( throw PlatformException(
code: error['code'], code: error['code'] as String,
message: error['message'], message: error['message'] as String,
details: error['details']); details: error['details'],
);
} else { } else {
// noop // noop
} }

@ -190,7 +190,7 @@ class _BookDetailState extends State<BookDetail> {
), ),
SizedBox(height: 12), SizedBox(height: 12),
Text( Text(
book.description, book.summary,
style: TextStyle(color: Colors.grey.shade600, height: 1.24), style: TextStyle(color: Colors.grey.shade600, height: 1.24),
), ),
], ],

@ -8,7 +8,7 @@ class Book {
String title; String title;
String subtitle; String subtitle;
String author; String author;
String description; String summary;
String publishDate; String publishDate;
int pageCount; int pageCount;
// Thumbnail thumbnail; // Thumbnail thumbnail;

@ -28,14 +28,14 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.5.0-nullsafety.3" version: "2.5.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0-nullsafety.3" version: "2.1.0"
build: build:
dependency: transitive dependency: transitive
description: description:
@ -63,14 +63,14 @@ packages:
name: characters name: characters
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0-nullsafety.5" version: "1.1.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0-nullsafety.3" version: "1.2.0"
cli_util: cli_util:
dependency: transitive dependency: transitive
description: description:
@ -84,7 +84,7 @@ packages:
name: clock name: clock
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0-nullsafety.3" version: "1.1.0"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
@ -98,7 +98,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0-nullsafety.5" version: "1.15.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -126,7 +126,7 @@ packages:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0-nullsafety.3" version: "1.2.0"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -185,14 +185,14 @@ packages:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.10-nullsafety.3" version: "0.12.10"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0-nullsafety.6" version: "1.3.0"
mockito: mockito:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -227,7 +227,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0-nullsafety.3" version: "1.8.0"
pedantic: pedantic:
dependency: transitive dependency: transitive
description: description:
@ -274,56 +274,56 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.0-nullsafety.4" version: "1.8.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.10.0-nullsafety.6" version: "1.10.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0-nullsafety.3" version: "2.1.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.0-nullsafety.3" version: "1.1.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0-nullsafety.3" version: "1.2.0"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.19-nullsafety.6" version: "0.2.19"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0-nullsafety.5" version: "1.3.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0-nullsafety.5" version: "2.1.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@ -339,4 +339,4 @@ packages:
source: hosted source: hosted
version: "2.2.1" version: "2.2.1"
sdks: sdks:
dart: ">=2.12.0-0.0 <3.0.0" dart: ">=2.12.0 <3.0.0"

@ -0,0 +1,8 @@
#!/bin/sh
flutter pub run pigeon --input pigeon/schema.dart \
--dart_out lib/api.dart \
--objc_header_out ../ios_books/IosBooks/api.h \
--objc_source_out ../ios_books/IosBooks/api.m \
--objc_prefix BK \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"

@ -0,0 +1,2 @@
xcuserdata
Pods

@ -0,0 +1,463 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objects = {
/* Begin PBXBuildFile section */
00365BF7846F71A1052D8F66 /* Pods_IosBooks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEE09DC86DF77B0A62A53D22 /* Pods_IosBooks.framework */; };
0DDE4C3B25E0390700389930 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE4C3A25E0390700389930 /* AppDelegate.swift */; };
0DDE4C3D25E0390700389930 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE4C3C25E0390700389930 /* SceneDelegate.swift */; };
0DDE4C3F25E0390700389930 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE4C3E25E0390700389930 /* ViewController.swift */; };
0DDE4C4225E0390700389930 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0DDE4C4025E0390700389930 /* Main.storyboard */; };
0DDE4C4425E0390700389930 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0DDE4C4325E0390700389930 /* Assets.xcassets */; };
0DDE4C4725E0390700389930 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0DDE4C4525E0390700389930 /* LaunchScreen.storyboard */; };
0DDE4C5725E041B700389930 /* BookCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE4C5625E041B700389930 /* BookCell.swift */; };
0DDE4C5C25E0752A00389930 /* api.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DDE4C5B25E0752A00389930 /* api.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0DDE4C3725E0390700389930 /* IosBooks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IosBooks.app; sourceTree = BUILT_PRODUCTS_DIR; };
0DDE4C3A25E0390700389930 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
0DDE4C3C25E0390700389930 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
0DDE4C3E25E0390700389930 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
0DDE4C4125E0390700389930 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
0DDE4C4325E0390700389930 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0DDE4C4625E0390700389930 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
0DDE4C4825E0390700389930 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0DDE4C5625E041B700389930 /* BookCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookCell.swift; sourceTree = "<group>"; };
0DDE4C5925E0752900389930 /* IosBooks-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IosBooks-Bridging-Header.h"; sourceTree = "<group>"; };
0DDE4C5A25E0752A00389930 /* api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = api.h; sourceTree = "<group>"; };
0DDE4C5B25E0752A00389930 /* api.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = api.m; sourceTree = "<group>"; };
18154B6C0196BC72EA210903 /* Pods-IosBooks.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IosBooks.release.xcconfig"; path = "Target Support Files/Pods-IosBooks/Pods-IosBooks.release.xcconfig"; sourceTree = "<group>"; };
CC7F3EDAABB4C083AD5BFC47 /* Pods-IosBooks.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IosBooks.debug.xcconfig"; path = "Target Support Files/Pods-IosBooks/Pods-IosBooks.debug.xcconfig"; sourceTree = "<group>"; };
DEE09DC86DF77B0A62A53D22 /* Pods_IosBooks.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IosBooks.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0DDE4C3425E0390700389930 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
00365BF7846F71A1052D8F66 /* Pods_IosBooks.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0DDE4C2E25E0390700389930 = {
isa = PBXGroup;
children = (
0DDE4C3925E0390700389930 /* IosBooks */,
0DDE4C3825E0390700389930 /* Products */,
1CA615579663E7DAA193BE81 /* Pods */,
4E1F60927412758AE8CBF737 /* Frameworks */,
);
sourceTree = "<group>";
};
0DDE4C3825E0390700389930 /* Products */ = {
isa = PBXGroup;
children = (
0DDE4C3725E0390700389930 /* IosBooks.app */,
);
name = Products;
sourceTree = "<group>";
};
0DDE4C3925E0390700389930 /* IosBooks */ = {
isa = PBXGroup;
children = (
0DDE4C5A25E0752A00389930 /* api.h */,
0DDE4C5B25E0752A00389930 /* api.m */,
0DDE4C3A25E0390700389930 /* AppDelegate.swift */,
0DDE4C3C25E0390700389930 /* SceneDelegate.swift */,
0DDE4C3E25E0390700389930 /* ViewController.swift */,
0DDE4C4025E0390700389930 /* Main.storyboard */,
0DDE4C4325E0390700389930 /* Assets.xcassets */,
0DDE4C4525E0390700389930 /* LaunchScreen.storyboard */,
0DDE4C4825E0390700389930 /* Info.plist */,
0DDE4C5625E041B700389930 /* BookCell.swift */,
0DDE4C5925E0752900389930 /* IosBooks-Bridging-Header.h */,
);
path = IosBooks;
sourceTree = "<group>";
};
1CA615579663E7DAA193BE81 /* Pods */ = {
isa = PBXGroup;
children = (
CC7F3EDAABB4C083AD5BFC47 /* Pods-IosBooks.debug.xcconfig */,
18154B6C0196BC72EA210903 /* Pods-IosBooks.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
4E1F60927412758AE8CBF737 /* Frameworks */ = {
isa = PBXGroup;
children = (
DEE09DC86DF77B0A62A53D22 /* Pods_IosBooks.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0DDE4C3625E0390700389930 /* IosBooks */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0DDE4C4B25E0390700389930 /* Build configuration list for PBXNativeTarget "IosBooks" */;
buildPhases = (
10D6942EFE7900338BEA50F9 /* [CP] Check Pods Manifest.lock */,
676852EE9ED16CAB1E3D2710 /* [CP] Prepare Artifacts */,
887B098B8DCF409FE0F1E164 /* [CP-User] Run Flutter Build flutter_module_books Script */,
0DDE4C3325E0390700389930 /* Sources */,
0DDE4C3425E0390700389930 /* Frameworks */,
0DDE4C3525E0390700389930 /* Resources */,
F82F2089B06A5489DA98C8B9 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = IosBooks;
productName = IosBooks;
productReference = 0DDE4C3725E0390700389930 /* IosBooks.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0DDE4C2F25E0390700389930 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1220;
LastUpgradeCheck = 1220;
TargetAttributes = {
0DDE4C3625E0390700389930 = {
CreatedOnToolsVersion = 12.2;
LastSwiftMigration = 1220;
};
};
};
buildConfigurationList = 0DDE4C3225E0390700389930 /* Build configuration list for PBXProject "IosBooks" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0DDE4C2E25E0390700389930;
productRefGroup = 0DDE4C3825E0390700389930 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0DDE4C3625E0390700389930 /* IosBooks */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0DDE4C3525E0390700389930 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0DDE4C4725E0390700389930 /* LaunchScreen.storyboard in Resources */,
0DDE4C4425E0390700389930 /* Assets.xcassets in Resources */,
0DDE4C4225E0390700389930 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
10D6942EFE7900338BEA50F9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-IosBooks-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;
};
676852EE9ED16CAB1E3D2710 /* [CP] Prepare Artifacts */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-artifacts-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Prepare Artifacts";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-artifacts-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-artifacts.sh\"\n";
showEnvVarsInLog = 0;
};
887B098B8DCF409FE0F1E164 /* [CP-User] Run Flutter Build flutter_module_books Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
name = "[CP-User] Run Flutter Build flutter_module_books Script";
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\nset -u\nsource \"${SRCROOT}/../flutter_module_books/.ios/Flutter/flutter_export_environment.sh\"\nexport VERBOSE_SCRIPT_LOGGING=1 && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build";
};
F82F2089B06A5489DA98C8B9 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-IosBooks/Pods-IosBooks-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0DDE4C3325E0390700389930 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0DDE4C5725E041B700389930 /* BookCell.swift in Sources */,
0DDE4C3F25E0390700389930 /* ViewController.swift in Sources */,
0DDE4C5C25E0752A00389930 /* api.m in Sources */,
0DDE4C3B25E0390700389930 /* AppDelegate.swift in Sources */,
0DDE4C3D25E0390700389930 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0DDE4C4025E0390700389930 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
0DDE4C4125E0390700389930 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
0DDE4C4525E0390700389930 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
0DDE4C4625E0390700389930 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0DDE4C4925E0390700389930 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
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_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
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 = 14.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
0DDE4C4A25E0390700389930 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
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_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
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 = 14.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
0DDE4C4C25E0390700389930 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = CC7F3EDAABB4C083AD5BFC47 /* Pods-IosBooks.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5B6X25244C;
INFOPLIST_FILE = IosBooks/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.samples.IosBooks;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "IosBooks/IosBooks-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
0DDE4C4D25E0390700389930 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 18154B6C0196BC72EA210903 /* Pods-IosBooks.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5B6X25244C;
INFOPLIST_FILE = IosBooks/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.samples.IosBooks;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "IosBooks/IosBooks-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0DDE4C3225E0390700389930 /* Build configuration list for PBXProject "IosBooks" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0DDE4C4925E0390700389930 /* Debug */,
0DDE4C4A25E0390700389930 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0DDE4C4B25E0390700389930 /* Build configuration list for PBXNativeTarget "IosBooks" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0DDE4C4C25E0390700389930 /* Debug */,
0DDE4C4D25E0390700389930 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0DDE4C2F25E0390700389930 /* Project object */;
}

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:IosBooks.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

@ -0,0 +1,37 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import Flutter
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var engine: FlutterEngine = {
let result = FlutterEngine.init(name: "Books")
// This could be `run` earlier in the app to avoid the overhead of doing it the first time the
// engine is needed.
result.run()
return result
}()
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
return true
}
func application(
_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(
_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {
}
}

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="b8i-Fj-lA1">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17505"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Navigation Controller-->
<scene sceneID="srE-pH-qZb">
<objects>
<navigationController id="b8i-Fj-lA1" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" id="wTo-xw-305">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" red="0.38431372549019605" green="0.0" blue="0.93333333333333335" alpha="0.84705882352941175" colorSpace="calibratedRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" systemColor="systemGray6Color"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="Xp0-05-6gn" kind="relationship" relationship="rootViewController" id="yik-Yg-HdC"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="NW2-DP-JZL" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1328" y="-17"/>
</scene>
<!--Books-->
<scene sceneID="Ywb-fB-wBN">
<objects>
<tableViewController title="Books" id="Xp0-05-6gn" customClass="ViewController" customModule="IosBooks" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" allowsSelection="NO" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="uCy-ec-yGR">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="BookCell" rowHeight="190" id="SBb-uI-gbV" customClass="BookCell" customModule="IosBooks" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="414" height="190"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SBb-uI-gbV" id="C7V-w9-p66">
<rect key="frame" x="0.0" y="0.0" width="414" height="190"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Book Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7KN-aJ-DT5">
<rect key="frame" x="20" y="11" width="374" height="29"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Uh5-nw-lRt">
<rect key="frame" x="20" y="48" width="374" height="41"/>
<string key="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc velit orci, varius tincidunt nisi ac, porta porta ipsum. Pellentesque feugiat consequat massa, facilisis euismod turpis aliquam at. Suspendisse mollis volutpat lacinia. Aenean tristique porttitor purus, eu porta sem tempor sit amet. </string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="By: Foobar F. Foobar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="76v-Ju-4Wc">
<rect key="frame" x="20" y="111" width="374" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="b0u-fM-VM6">
<rect key="frame" x="350" y="140" width="44" height="44"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="44" id="Vf7-pJ-LZ3"/>
<constraint firstAttribute="height" constant="44" id="cfM-g4-ptv"/>
</constraints>
<state key="normal" title="Edit"/>
</button>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="b0u-fM-VM6" secondAttribute="bottom" constant="6" id="BPN-jO-sVu"/>
<constraint firstItem="7KN-aJ-DT5" firstAttribute="leading" secondItem="C7V-w9-p66" secondAttribute="leadingMargin" id="DsW-Gq-sjE"/>
<constraint firstItem="7KN-aJ-DT5" firstAttribute="trailing" secondItem="C7V-w9-p66" secondAttribute="trailingMargin" id="IVX-uA-An6"/>
<constraint firstItem="7KN-aJ-DT5" firstAttribute="top" secondItem="C7V-w9-p66" secondAttribute="topMargin" id="Iip-4a-2kS"/>
<constraint firstItem="76v-Ju-4Wc" firstAttribute="leading" secondItem="C7V-w9-p66" secondAttribute="leadingMargin" id="ZbD-YJ-kaV"/>
<constraint firstItem="76v-Ju-4Wc" firstAttribute="top" secondItem="Uh5-nw-lRt" secondAttribute="bottom" constant="22" id="cyp-xR-7If"/>
<constraint firstItem="b0u-fM-VM6" firstAttribute="trailing" secondItem="C7V-w9-p66" secondAttribute="trailingMargin" id="gSP-0I-VmO"/>
<constraint firstItem="b0u-fM-VM6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="C7V-w9-p66" secondAttribute="leadingMargin" id="gzq-Ig-PZI"/>
<constraint firstItem="b0u-fM-VM6" firstAttribute="top" secondItem="76v-Ju-4Wc" secondAttribute="bottom" constant="8" symbolic="YES" id="lCb-GM-BvA"/>
<constraint firstItem="Uh5-nw-lRt" firstAttribute="trailing" secondItem="C7V-w9-p66" secondAttribute="trailingMargin" id="p6I-sS-CN3"/>
<constraint firstItem="Uh5-nw-lRt" firstAttribute="leading" secondItem="C7V-w9-p66" secondAttribute="leadingMargin" id="qcT-uN-mqo"/>
<constraint firstItem="Uh5-nw-lRt" firstAttribute="top" secondItem="7KN-aJ-DT5" secondAttribute="bottom" constant="8" symbolic="YES" id="r2u-eT-RhX"/>
<constraint firstItem="76v-Ju-4Wc" firstAttribute="trailing" secondItem="C7V-w9-p66" secondAttribute="trailingMargin" id="zc4-dZ-JcM"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="byLine" destination="76v-Ju-4Wc" id="9Ky-Yc-aXU"/>
<outlet property="editButton" destination="b0u-fM-VM6" id="q99-MH-ThV"/>
<outlet property="subtitle" destination="Uh5-nw-lRt" id="UGS-IB-WV1"/>
<outlet property="title" destination="7KN-aJ-DT5" id="a5N-rW-azA"/>
</connections>
</tableViewCell>
</prototypes>
<sections/>
<connections>
<outlet property="dataSource" destination="Xp0-05-6gn" id="nso-Wx-y17"/>
<outlet property="delegate" destination="Xp0-05-6gn" id="Gk5-ND-hmv"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="Mr1-af-Ogz"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="17x-S3-agc" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-371.01449275362324" y="-17.410714285714285"/>
</scene>
</scenes>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGray6Color">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>

@ -0,0 +1,8 @@
import UIKit
class BookCell: UITableViewCell {
@IBOutlet weak var title: UILabel!
@IBOutlet weak var subtitle: UILabel!
@IBOutlet weak var byLine: UILabel!
@IBOutlet weak var editButton: UIButton!
}

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

@ -0,0 +1,5 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "api.h"

@ -0,0 +1,32 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene, willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
}
func sceneDidBecomeActive(_ scene: UIScene) {
}
func sceneWillResignActive(_ scene: UIScene) {
}
func sceneWillEnterForeground(_ scene: UIScene) {
}
func sceneDidEnterBackground(_ scene: UIScene) {
}
}

@ -0,0 +1,131 @@
// Copyright 2020 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import Flutter
import UIKit
class ViewController: UITableViewController, BKHostBookApi {
private var books: [BKBook] = []
private var api: BKFlutterBookApi!
private var editingIndex: Int = -1
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Books"
let appDelegate = UIApplication.shared.delegate as! AppDelegate
BKHostBookApiSetup(appDelegate.engine.binaryMessenger, self)
api = BKFlutterBookApi.init(binaryMessenger: appDelegate.engine.binaryMessenger)
if let url = URL(
string: "https://www.googleapis.com/books/v1/volumes?q=greenwood+tulsa&maxResults=15")
{
self.loadBooks(url: url) { (newBooks) in
if let newBooks = newBooks {
self.books = newBooks
self.tableView.reloadData()
}
}
}
}
/**
Loads a JSON file from the supplied URL, parses it and calls the callback with the array of
parsed books on the main thread.
*/
func loadBooks(url: URL, completion: @escaping ([BKBook]?) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: [])
as? [String: Any]
{
var newBooks: [BKBook] = []
for item in json["items"] as! [[String: Any]] {
let volumeInfo = item["volumeInfo"] as! [String: Any]
let title = volumeInfo["title"] as! String
let subtitle = volumeInfo["subtitle"] as! String?
let authors = (volumeInfo["authors"] as! [String]).joined(separator: " & ")
let pageCount = volumeInfo["pageCount"] as! Int32
let publishedDate = volumeInfo["publishedDate"] as! String
let summary = volumeInfo["description"] as! String
let book: BKBook = BKBook.init()
book.author = authors
book.title = title
book.subtitle = subtitle
book.title = title
book.pageCount = NSNumber.init(value: pageCount)
book.publishDate = publishedDate
book.summary = summary
newBooks.append(book)
}
DispatchQueue.main.async {
completion(newBooks)
}
}
} catch let error {
print("json decode error: \(error)")
completion(nil)
}
}
}.resume()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.books.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell
{
let cell: BookCell = self.tableView.dequeueReusableCell(withIdentifier: "BookCell") as! BookCell
let bookInfo = books[indexPath.row]
cell.title.text = bookInfo.title
cell.subtitle.text = bookInfo.subtitle
if let author = bookInfo.author {
cell.byLine.text = "by: \(author)"
}
weak var weakSelf = self
let editAction = UIAction(title: "Edit") { (action) in
if let weakSelf = weakSelf {
weakSelf.editItem(index: indexPath.row)
}
}
cell.editButton.removeTarget(nil, action: nil, for: .allEvents)
cell.editButton.addAction(editAction, for: UIControl.Event.touchUpInside)
return cell
}
/**
Presents the FlutterViewController that edits the book at the supplied index.
*/
func editItem(index: Int) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let flutterViewController = FlutterViewController.init(
engine: appDelegate.engine, nibName: nil, bundle: nil)
self.editingIndex = index
api.displayBookDetails(self.books[index]) { (error) in
if let error = error {
print(error)
}
}
self.present(flutterViewController, animated: true, completion: nil)
}
/**
Called by Pigeon when the FlutterViewController is dismissed without accepting any edits.
*/
func cancel(_ error: AutoreleasingUnsafeMutablePointer<FlutterError?>) {
self.editingIndex = -1
self.dismiss(animated: true, completion: nil)
}
/**
Called by Pigeon when edits to the book are accepted in the FlutterViewController.
*/
func finishEditing(_ input: BKBook, error: AutoreleasingUnsafeMutablePointer<FlutterError?>) {
self.books[editingIndex] = input
self.tableView.reloadData()
self.editingIndex = -1
self.dismiss(animated: true, completion: nil)
}
}

@ -0,0 +1,32 @@
// Autogenerated from Pigeon (v0.1.17), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import <Foundation/Foundation.h>
@protocol FlutterBinaryMessenger;
@class FlutterError;
@class FlutterStandardTypedData;
NS_ASSUME_NONNULL_BEGIN
@class BKBook;
@interface BKBook : NSObject
@property(nonatomic, copy, nullable) NSString * title;
@property(nonatomic, copy, nullable) NSString * subtitle;
@property(nonatomic, copy, nullable) NSString * author;
@property(nonatomic, copy, nullable) NSString * summary;
@property(nonatomic, copy, nullable) NSString * publishDate;
@property(nonatomic, strong, nullable) NSNumber * pageCount;
@end
@interface BKFlutterBookApi : NSObject
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
- (void)displayBookDetails:(BKBook*)input completion:(void(^)(NSError* _Nullable))completion;
@end
@protocol BKHostBookApi
-(void)cancel:(FlutterError *_Nullable *_Nonnull)error;
-(void)finishEditingBook:(BKBook*)input error:(FlutterError *_Nullable *_Nonnull)error;
@end
extern void BKHostBookApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<BKHostBookApi> _Nullable api);
NS_ASSUME_NONNULL_END

@ -0,0 +1,122 @@
// Autogenerated from Pigeon (v0.1.17), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import "api.h"
#import <Flutter/Flutter.h>
#if !__has_feature(objc_arc)
#error File requires ARC to be enabled.
#endif
static NSDictionary* wrapResult(NSDictionary *result, FlutterError *error) {
NSDictionary *errorDict = (NSDictionary *)[NSNull null];
if (error) {
errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
(error.code ? error.code : [NSNull null]), @"code",
(error.message ? error.message : [NSNull null]), @"message",
(error.details ? error.details : [NSNull null]), @"details",
nil];
}
return [NSDictionary dictionaryWithObjectsAndKeys:
(result ? result : [NSNull null]), @"result",
errorDict, @"error",
nil];
}
@interface BKBook ()
+(BKBook*)fromMap:(NSDictionary*)dict;
-(NSDictionary*)toMap;
@end
@implementation BKBook
+(BKBook*)fromMap:(NSDictionary*)dict {
BKBook* result = [[BKBook alloc] init];
result.title = dict[@"title"];
if ((NSNull *)result.title == [NSNull null]) {
result.title = nil;
}
result.subtitle = dict[@"subtitle"];
if ((NSNull *)result.subtitle == [NSNull null]) {
result.subtitle = nil;
}
result.author = dict[@"author"];
if ((NSNull *)result.author == [NSNull null]) {
result.author = nil;
}
result.summary = dict[@"summary"];
if ((NSNull *)result.summary == [NSNull null]) {
result.summary = nil;
}
result.publishDate = dict[@"publishDate"];
if ((NSNull *)result.publishDate == [NSNull null]) {
result.publishDate = nil;
}
result.pageCount = dict[@"pageCount"];
if ((NSNull *)result.pageCount == [NSNull null]) {
result.pageCount = nil;
}
return result;
}
-(NSDictionary*)toMap {
return [NSDictionary dictionaryWithObjectsAndKeys:(self.title ? self.title : [NSNull null]), @"title", (self.subtitle ? self.subtitle : [NSNull null]), @"subtitle", (self.author ? self.author : [NSNull null]), @"author", (self.summary ? self.summary : [NSNull null]), @"summary", (self.publishDate ? self.publishDate : [NSNull null]), @"publishDate", (self.pageCount ? self.pageCount : [NSNull null]), @"pageCount", nil];
}
@end
@interface BKFlutterBookApi ()
@property (nonatomic, strong) NSObject<FlutterBinaryMessenger>* binaryMessenger;
@end
@implementation BKFlutterBookApi
- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger>*)binaryMessenger {
self = [super init];
if (self) {
self.binaryMessenger = binaryMessenger;
}
return self;
}
- (void)displayBookDetails:(BKBook*)input completion:(void(^)(NSError* _Nullable))completion {
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel
messageChannelWithName:@"dev.flutter.pigeon.FlutterBookApi.displayBookDetails"
binaryMessenger:self.binaryMessenger];
NSDictionary* inputMap = [input toMap];
[channel sendMessage:inputMap reply:^(id reply) {
completion(nil);
}];
}
@end
void BKHostBookApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<BKHostBookApi> api) {
{
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel
messageChannelWithName:@"dev.flutter.pigeon.HostBookApi.cancel"
binaryMessenger:binaryMessenger];
if (api) {
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
FlutterError *error;
[api cancel:&error];
callback(wrapResult(nil, error));
}];
}
else {
[channel setMessageHandler:nil];
}
}
{
FlutterBasicMessageChannel *channel =
[FlutterBasicMessageChannel
messageChannelWithName:@"dev.flutter.pigeon.HostBookApi.finishEditingBook"
binaryMessenger:binaryMessenger];
if (api) {
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
FlutterError *error;
BKBook *input = [BKBook fromMap:message];
[api finishEditingBook:input error:&error];
callback(wrapResult(nil, error));
}];
}
else {
[channel setMessageHandler:nil];
}
}
}

@ -0,0 +1,12 @@
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
flutter_application_path = '../flutter_module_books/'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'IosBooks' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for IosBooks
install_all_flutter_pods(flutter_application_path)
end

@ -0,0 +1,28 @@
PODS:
- Flutter (1.0.0)
- flutter_module_books (0.0.1):
- Flutter
- FlutterPluginRegistrant (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `../flutter_module_books/.ios/Flutter/engine`)
- flutter_module_books (from `../flutter_module_books/.ios/Flutter`)
- FlutterPluginRegistrant (from `../flutter_module_books/.ios/Flutter/FlutterPluginRegistrant`)
EXTERNAL SOURCES:
Flutter:
:path: "../flutter_module_books/.ios/Flutter/engine"
flutter_module_books:
:path: "../flutter_module_books/.ios/Flutter"
FlutterPluginRegistrant:
:path: "../flutter_module_books/.ios/Flutter/FlutterPluginRegistrant"
SPEC CHECKSUMS:
Flutter: ac41d61a47ae5bf8195a5598d2d63754888ec0d5
flutter_module_books: 537fdde264c187fc97299f730dd35974055cac20
FlutterPluginRegistrant: 2afd5ea46d3a949472c9b7da6462d8fbf7d8b16e
PODFILE CHECKSUM: 96e3c2df11e96c20ece1d4185fde634ec6324fcc
COCOAPODS: 1.9.3

@ -2,6 +2,47 @@
set -e set -e
###############################################################################
# Helper functions
###############################################################################
# Runs `packages get` on given flutter module.
# $1 = path to flutter module
function flutter_packages_get() {
echo "Fetching dependencies and building '$1'."
pushd $1
flutter packages get
popd
}
# Runs xcode build for Debug and Release.
# $1 = path to directory containing the xcode project
# $2 = name of the xcworkspace
# $3 = name of the scheme
function build() {
echo "== Testing '$1' on Flutter's $FLUTTER_VERSION channel =="
pushd "$1"
pod install
xcodebuild -workspace "$2" \
-scheme "$3" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Debug | xcpretty
xcodebuild -workspace "$2" \
-scheme "$3" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
-destination generic/platform=iOS | xcpretty
popd
}
###############################################################################
# Building preconditions
###############################################################################
echo "Pre-caching ios artifacts, such as the Flutter.framework" echo "Pre-caching ios artifacts, such as the Flutter.framework"
flutter precache --no-web --no-linux --no-windows --no-fuchsia --no-android --no-macos flutter precache --no-web --no-linux --no-windows --no-fuchsia --no-android --no-macos
@ -11,56 +52,19 @@ flutter packages get
flutter build ios-framework --xcframework --output="$(pwd)/../ios_using_prebuilt_module/Flutter" flutter build ios-framework --xcframework --output="$(pwd)/../ios_using_prebuilt_module/Flutter"
popd popd
echo "Fetching dependencies for 'plugin/flutter_module_using_plugin'." flutter_packages_get "add_to_app/books/flutter_module_books"
pushd add_to_app/plugin/flutter_module_using_plugin flutter_packages_get "add_to_app/fullscreen/flutter_module"
flutter packages get flutter_packages_get "add_to_app/multiple_flutters/multiple_flutters_module"
popd flutter_packages_get "add_to_app/plugin/flutter_module_using_plugin"
echo "Fetching dependencies and building 'fullscreen/flutter_module'." ###############################################################################
pushd add_to_app/fullscreen/flutter_module # Build projects
flutter packages get ###############################################################################
popd
echo "Fetching dependencies and building 'multiple_flutters/multiple_flutters_module'." build "add_to_app/books/ios_books" "IosBooks.xcworkspace" "IosBooks"
pushd add_to_app/multiple_flutters/multiple_flutters_module build "add_to_app/fullscreen/ios_fullscreen" "IOSFullScreen.xcworkspace" "IOSFullScreen"
flutter packages get build "add_to_app/multiple_flutters/multiple_flutters_ios" "MultipleFluttersIos.xcworkspace" "MultipleFluttersIos"
popd build "add_to_app/plugin/ios_using_plugin" "IOSUsingPlugin.xcworkspace" "IOSUsingPlugin"
echo "== Testing 'add_to_app/fullscreen/ios_fullscreen' on Flutter's $FLUTTER_VERSION channel =="
pushd "add_to_app/fullscreen/ios_fullscreen"
pod install
xcodebuild -workspace "IOSFullScreen.xcworkspace" \
-scheme "IOSFullScreen" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Debug | xcpretty
xcodebuild -workspace "IOSFullScreen.xcworkspace" \
-scheme "IOSFullScreen" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
-destination generic/platform=iOS | xcpretty
popd
echo "== Testing 'add_to_app/plugin/ios_using_plugin' on Flutter's $FLUTTER_VERSION channel =="
pushd "add_to_app/plugin/ios_using_plugin"
pod install
xcodebuild -workspace "IOSUsingPlugin.xcworkspace" \
-scheme "IOSUsingPlugin" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Debug | xcpretty
xcodebuild -workspace "IOSUsingPlugin.xcworkspace" \
-scheme "IOSUsingPlugin" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
-destination generic/platform=iOS | xcpretty
popd
echo "== Testing 'add_to_app/prebuilt_module/ios_using_prebuilt_module' on Flutter's $FLUTTER_VERSION channel ==" echo "== Testing 'add_to_app/prebuilt_module/ios_using_prebuilt_module' on Flutter's $FLUTTER_VERSION channel =="
pushd "add_to_app/prebuilt_module/ios_using_prebuilt_module" pushd "add_to_app/prebuilt_module/ios_using_prebuilt_module"
@ -76,23 +80,4 @@ COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
popd popd
echo "== Testing 'add_to_app/multiple_flutters/multiple_flutters_ios' on Flutter's $FLUTTER_VERSION channel =="
pushd "add_to_app/multiple_flutters/multiple_flutters_ios"
pod install
xcodebuild -workspace "MultipleFluttersIos.xcworkspace" \
-scheme "MultipleFluttersIos" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Debug | xcpretty
xcodebuild -workspace "MultipleFluttersIos.xcworkspace" \
-scheme "MultipleFluttersIos" CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY=- EXPANDED_CODE_SIGN_IDENTITY=- \
COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
-destination generic/platform=iOS | xcpretty
popd
echo "-- Success --" echo "-- Success --"

Loading…
Cancel
Save