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
references the Google Books API as a data source. These same libraries also
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
idiomatic platform API conventions rather than Flutter conventions.
* 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
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
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
@ -36,10 +38,13 @@ page.
* If the `schema.dart` is modified, the generated classes can be updated with
```bash
flutter pub run pigeon \
--input pigeon/schema.dart \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"
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"
```
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.
# For iOS builds:
# TODO iOS sample
cd ../ios_books
pod install
open ios_books/IosBooks.xcworkspace
```
## Requirements
* Flutter
* Android Studio
* Cocoapods (iOS)
## 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
package dev.flutter.example.books;
import java.util.HashMap;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import java.util.ArrayList;
import java.util.HashMap;
/** Generated class from Pigeon. */
@SuppressWarnings("unused")
public class Api {
/** Generated class from Pigeon that represents data sent in messages. */
@ -26,9 +27,9 @@ public class Api {
public String getAuthor() { return author; }
public void setAuthor(String setterArg) { this.author = setterArg; }
private String description;
public String getDescription() { return description; }
public void setDescription(String setterArg) { this.description = setterArg; }
private String summary;
public String getSummary() { return summary; }
public void setSummary(String setterArg) { this.summary = setterArg; }
private String publishDate;
public String getPublishDate() { return publishDate; }
@ -39,30 +40,36 @@ public class Api {
public void setPageCount(Long setterArg) { this.pageCount = setterArg; }
HashMap toMap() {
HashMap<String, Object> toMapResult = new HashMap<String, Object>();
HashMap<String, Object> toMapResult = new HashMap<>();
toMapResult.put("title", title);
toMapResult.put("subtitle", subtitle);
toMapResult.put("author", author);
toMapResult.put("description", description);
toMapResult.put("summary", summary);
toMapResult.put("publishDate", publishDate);
toMapResult.put("pageCount", pageCount);
return toMapResult;
}
static Book fromMap(HashMap map) {
Book fromMapResult = new Book();
fromMapResult.title = (String)map.get("title");
fromMapResult.subtitle = (String)map.get("subtitle");
fromMapResult.author = (String)map.get("author");
fromMapResult.description = (String)map.get("description");
fromMapResult.publishDate = (String)map.get("publishDate");
fromMapResult.pageCount = (map.get("pageCount") instanceof Integer) ? (Integer)map.get("pageCount") : (Long)map.get("pageCount");
Object title = map.get("title");
fromMapResult.title = (String)title;
Object subtitle = map.get("subtitle");
fromMapResult.subtitle = (String)subtitle;
Object author = map.get("author");
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;
}
}
/** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/
public static class FlutterBookApi {
private BinaryMessenger binaryMessenger;
private final BinaryMessenger binaryMessenger;
public FlutterBookApi(BinaryMessenger argBinaryMessenger){
this.binaryMessenger = argBinaryMessenger;
}
@ -71,12 +78,10 @@ public class Api {
}
public void displayBookDetails(Book argInput, Reply<Void> callback) {
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();
channel.send(inputMap, new BasicMessageChannel.Reply<Object>() {
public void reply(Object channelReply) {
callback.reply(null);
}
channel.send(inputMap, channelReply -> {
callback.reply(null);
});
}
}
@ -90,20 +95,18 @@ public class Api {
static void setup(BinaryMessenger binaryMessenger, HostBookApi api) {
{
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) {
channel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() {
public void onMessage(Object message, BasicMessageChannel.Reply<Object> reply) {
HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>();
try {
api.cancel();
wrapped.put("result", null);
}
catch (Exception exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
channel.setMessageHandler((message, reply) -> {
HashMap<String, HashMap> wrapped = new HashMap<>();
try {
api.cancel();
wrapped.put("result", null);
}
catch (Exception exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
@ -111,21 +114,20 @@ public class Api {
}
{
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) {
channel.setMessageHandler(new BasicMessageChannel.MessageHandler<Object>() {
public void onMessage(Object message, BasicMessageChannel.Reply<Object> reply) {
channel.setMessageHandler((message, reply) -> {
HashMap<String, HashMap> wrapped = new HashMap<>();
try {
@SuppressWarnings("ConstantConditions")
Book input = Book.fromMap((HashMap)message);
HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>();
try {
api.finishEditingBook(input);
wrapped.put("result", null);
}
catch (Exception exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
api.finishEditingBook(input);
wrapped.put("result", null);
}
catch (Exception exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
@ -134,9 +136,9 @@ public class Api {
}
}
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("code", null);
errorMap.put("code", exception.getClass().getSimpleName());
errorMap.put("details", null);
return errorMap;
}

@ -91,7 +91,7 @@ class MainActivity : AppCompatActivity() {
book.subtitle = volumeInfoJson.get("subtitle")?.asString
// Sorry co-authors, we're trying to keep this simple.
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.pageCount = volumeInfoJson.get("pageCount").asLong
books.add(book)

@ -16,10 +16,13 @@ in `pigeon/schema.dart` is updated, the generated classes can also be re-
generated using:
```shell
flutter pub run pigeon \
--input pigeon/schema.dart \
--java_out ../android_books/app/src/main/java/dev/flutter/example/books/Api.java \
--java_package "dev.flutter.example.books"
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"
```
## 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
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import
// @dart = 2.8
import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
import 'package:flutter/services.dart';
class Book {
String title;
String subtitle;
String author;
String description;
String summary;
String publishDate;
int pageCount;
// ignore: unused_element
Map<dynamic, dynamic> _toMap() {
final Map<dynamic, dynamic> pigeonMap = <dynamic, dynamic>{};
Object encode() {
final Map<Object, Object> pigeonMap = <Object, Object>{};
pigeonMap['title'] = title;
pigeonMap['subtitle'] = subtitle;
pigeonMap['author'] = author;
pigeonMap['description'] = description;
pigeonMap['summary'] = summary;
pigeonMap['publishDate'] = publishDate;
pigeonMap['pageCount'] = pageCount;
return pigeonMap;
}
// ignore: unused_element
static Book _fromMap(Map<dynamic, dynamic> pigeonMap) {
final Book result = Book();
result.title = pigeonMap['title'];
result.subtitle = pigeonMap['subtitle'];
result.author = pigeonMap['author'];
result.description = pigeonMap['description'];
result.publishDate = pigeonMap['publishDate'];
result.pageCount = pigeonMap['pageCount'];
return result;
static Book decode(Object message) {
final Map<Object, Object> pigeonMap = message as Map<Object, Object>;
return Book()
..title = pigeonMap['title'] as String
..subtitle = pigeonMap['subtitle'] as String
..author = pigeonMap['author'] as String
..summary = pigeonMap['summary'] as String
..publishDate = pigeonMap['publishDate'] as String
..pageCount = pigeonMap['pageCount'] as int;
}
}
@ -40,59 +44,71 @@ abstract class FlutterBookApi {
void displayBookDetails(Book arg);
static void setup(FlutterBookApi api) {
{
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.FlutterBookApi.displayBookDetails',
StandardMessageCodec());
channel.setMessageHandler((dynamic message) async {
final Map<dynamic, dynamic> mapMessage =
message as Map<dynamic, dynamic>;
final Book input = Book._fromMap(mapMessage);
api.displayBookDetails(input);
});
if (api == null) {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object message) async {
if (message == null) {
return;
}
final Book input = Book.decode(message);
api.displayBookDetails(input);
return;
});
}
}
}
}
class HostBookApi {
Future<void> cancel() async {
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.HostBookApi.cancel', StandardMessageCodec());
final Map<dynamic, dynamic> replyMap = await channel.send(null);
final Map<Object, Object> replyMap =
await channel.send(null) as Map<Object, Object>;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null);
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: 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(
code: error['code'],
message: error['message'],
details: error['details']);
code: error['code'] as String,
message: error['message'] as String,
details: error['details'],
);
} else {
// noop
}
}
Future<void> finishEditingBook(Book arg) async {
final Map<dynamic, dynamic> requestMap = arg._toMap();
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
final Object encoded = arg.encode();
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.HostBookApi.finishEditingBook',
StandardMessageCodec());
final Map<dynamic, dynamic> replyMap = await channel.send(requestMap);
final Map<Object, Object> replyMap =
await channel.send(encoded) as Map<Object, Object>;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: null);
code: 'channel-error',
message: 'Unable to establish connection on channel.',
details: 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(
code: error['code'],
message: error['message'],
details: error['details']);
code: error['code'] as String,
message: error['message'] as String,
details: error['details'],
);
} else {
// noop
}

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

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

@ -28,14 +28,14 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0-nullsafety.3"
version: "2.5.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.3"
version: "2.1.0"
build:
dependency: transitive
description:
@ -63,14 +63,14 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety.5"
version: "1.1.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety.3"
version: "1.2.0"
cli_util:
dependency: transitive
description:
@ -84,7 +84,7 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety.3"
version: "1.1.0"
code_builder:
dependency: transitive
description:
@ -98,7 +98,7 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0-nullsafety.5"
version: "1.15.0"
convert:
dependency: transitive
description:
@ -126,7 +126,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety.3"
version: "1.2.0"
file:
dependency: transitive
description:
@ -185,14 +185,14 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10-nullsafety.3"
version: "0.12.10"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.6"
version: "1.3.0"
mockito:
dependency: "direct dev"
description:
@ -227,7 +227,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0-nullsafety.3"
version: "1.8.0"
pedantic:
dependency: transitive
description:
@ -274,56 +274,56 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0-nullsafety.4"
version: "1.8.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0-nullsafety.6"
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.3"
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0-nullsafety.3"
version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0-nullsafety.3"
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.19-nullsafety.6"
version: "0.2.19"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.5"
version: "1.3.0"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0-nullsafety.5"
version: "2.1.0"
watcher:
dependency: transitive
description:
@ -339,4 +339,4 @@ packages:
source: hosted
version: "2.2.1"
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
###############################################################################
# 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"
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"
popd
echo "Fetching dependencies for 'plugin/flutter_module_using_plugin'."
pushd add_to_app/plugin/flutter_module_using_plugin
flutter packages get
popd
flutter_packages_get "add_to_app/books/flutter_module_books"
flutter_packages_get "add_to_app/fullscreen/flutter_module"
flutter_packages_get "add_to_app/multiple_flutters/multiple_flutters_module"
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
flutter packages get
popd
###############################################################################
# Build projects
###############################################################################
echo "Fetching dependencies and building 'multiple_flutters/multiple_flutters_module'."
pushd add_to_app/multiple_flutters/multiple_flutters_module
flutter packages get
popd
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
build "add_to_app/books/ios_books" "IosBooks.xcworkspace" "IosBooks"
build "add_to_app/fullscreen/ios_fullscreen" "IOSFullScreen.xcworkspace" "IOSFullScreen"
build "add_to_app/multiple_flutters/multiple_flutters_ios" "MultipleFluttersIos.xcworkspace" "MultipleFluttersIos"
build "add_to_app/plugin/ios_using_plugin" "IOSUsingPlugin.xcworkspace" "IOSUsingPlugin"
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"
@ -76,23 +80,4 @@ COMPILER_INDEX_STORE_ENABLE=NO CONFIGURATION=Release \
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 --"

Loading…
Cancel
Save