├── ios ├── Assets │ └── .gitkeep ├── Classes │ ├── FlutterTtsImprovedPlugin.h │ ├── FlutterTtsImprovedPlugin.m │ └── SwiftFlutterTtsImprovedPlugin.swift ├── .gitignore └── flutter_tts_improved.podspec ├── android ├── gradle.properties ├── settings.gradle ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── rdygo │ │ └── flutter_tts_improved │ │ └── FlutterTtsImprovedPlugin.java ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── build.gradle ├── example ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── rdygo │ │ │ │ │ │ └── flutter_tts_improved_example │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── build.gradle ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Podfile.lock │ └── Podfile ├── .metadata ├── README.md ├── test │ └── widget_test.dart ├── .gitignore ├── pubspec.yaml ├── lib │ └── main.dart └── pubspec.lock ├── .metadata ├── CHANGELOG.md ├── pubspec.yaml ├── test └── flutter_tts_improved_test.dart ├── LICENSE ├── .gitignore ├── pubspec.lock ├── README.md ├── lib └── flutter_tts_improved.dart └── analysis_options.yaml /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | 3 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'flutter_tts_improved' 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Classes/FlutterTtsImprovedPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FlutterTtsImprovedPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loushou/flutter_tts_improved/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 6 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Classes/FlutterTtsImprovedPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FlutterTtsImprovedPlugin.h" 2 | #import 3 | 4 | @implementation FlutterTtsImprovedPlugin 5 | + (void)registerWithRegistrar:(NSObject*)registrar { 6 | [SwiftFlutterTtsImprovedPlugin registerWithRegistrar:registrar]; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: cc949a8e8b9cf394b9290a8e80f87af3e207dce5 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.3 2 | 3 | * Formatted code according to dart pub specs 4 | 5 | ## 1.0.2 6 | 7 | * Fully tested on multiple iOS and Android devices and emulators 8 | 9 | ## 0.0.2 10 | 11 | * Fixed issue with iOS config that prevented plugin from working on iOS devices 12 | 13 | ## 0.0.1 14 | 15 | * Added the usage of the built-in Android and iOS Utterance APIs, when available 16 | * Added stub for older android APIs when Utterance API is not available (pre-android-26) 17 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/rdygo/flutter_tts_improved_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rdygo.flutter_tts_improved_example; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_tts_improved 2 | description: A fork of the Flutter_TTS plugin, that uses the progress reporters of the Utterance APIs, on both Android and iOS. 3 | version: 1.0.3 4 | author: Loushou 5 | homepage: https://github.com/loushou/flutter_tts_improved 6 | 7 | environment: 8 | sdk: ">=2.1.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | flutter: 19 | plugin: 20 | androidPackage: com.rdygo.flutter_tts_improved 21 | pluginClass: FlutterTtsImprovedPlugin 22 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # flutter_tts_improved_example 2 | 3 | Demonstrates how to use the flutter_tts_improved plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - flutter_tts_improved (0.0.1): 4 | - Flutter 5 | 6 | DEPENDENCIES: 7 | - Flutter (from `.symlinks/flutter/ios`) 8 | - flutter_tts_improved (from `.symlinks/plugins/flutter_tts_improved/ios`) 9 | 10 | EXTERNAL SOURCES: 11 | Flutter: 12 | :path: ".symlinks/flutter/ios" 13 | flutter_tts_improved: 14 | :path: ".symlinks/plugins/flutter_tts_improved/ios" 15 | 16 | SPEC CHECKSUMS: 17 | Flutter: 0e3d915762c693b495b44d77113d4970485de6ec 18 | flutter_tts_improved: 53fd47d204d6ef2ad5a9a8d9d4837a726fc9bf46 19 | 20 | PODFILE CHECKSUM: 10ae9c18d12c9ffc2275c9a159a3b1e281990db0 21 | 22 | COCOAPODS: 1.8.3 23 | -------------------------------------------------------------------------------- /test/flutter_tts_improved_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_tts_improved/flutter_tts_improved.dart'; 4 | 5 | void main() { 6 | const MethodChannel channel = MethodChannel('flutter_tts_improved'); 7 | 8 | setUp(() { 9 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 10 | return '42'; 11 | }); 12 | }); 13 | 14 | tearDown(() { 15 | channel.setMockMethodCallHandler(null); 16 | }); 17 | 18 | test('setSpeechRate', () async { 19 | FlutterTtsImproved tts = FlutterTtsImproved(); 20 | expect(await tts.setSpeechRate(1), '1'); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.rdygo.flutter_tts_improved' 2 | version '1.0.3' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.2.1' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | 24 | android { 25 | compileSdkVersion 28 26 | 27 | defaultConfig { 28 | minSdkVersion 21 29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 30 | } 31 | lintOptions { 32 | disable 'InvalidPackage' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/flutter_tts_improved.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'flutter_tts_improved' 6 | s.version = '1.0.3' 7 | s.summary = 'A fork of the Flutter_TTS plugin, that uses the progress reporters of the Utterance APIs, on both Android and iOS.' 8 | s.description = <<-DESC 9 | A fork of the Flutter_TTS plugin, that uses the progress reporters of the Utterance APIs, on both Android and iOS. 10 | DESC 11 | s.homepage = 'https://github.com/loushou/flutter_tts_improved' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Loushou' => 'life.42@gmail.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.ios.deployment_target = '8.0' 19 | s.swift_version = '5.0' 20 | s.static_framework = true 21 | end 22 | 23 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_tts_improved_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Daniel Lutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_tts_improved_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.rdygo.flutter_tts_improved_example" 37 | minSdkVersion 21 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_tts_improved_example 2 | description: Demonstrates how to use the flutter_tts_improved plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.1.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | # The following adds the Cupertino Icons font to your application. 13 | # Use with the CupertinoIcons class for iOS style icons. 14 | cupertino_icons: ^0.1.2 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | 20 | flutter_tts_improved: 21 | path: ../ 22 | 23 | # For information on the generic Dart part of this file, see the 24 | # following page: https://dart.dev/tools/pub/pubspec 25 | 26 | # The following section is specific to Flutter. 27 | flutter: 28 | 29 | # The following line ensures that the Material Icons font is 30 | # included with your application, so that you can use the icons in 31 | # the material Icons class. 32 | uses-material-design: true 33 | 34 | # To add assets to your application, add an assets section, like this: 35 | # assets: 36 | # - images/a_dot_burr.jpeg 37 | # - images/a_dot_ham.jpeg 38 | 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.dev/assets-and-images/#resolution-aware. 41 | 42 | # For details regarding adding assets from package dependencies, see 43 | # https://flutter.dev/assets-and-images/#from-packages 44 | 45 | # To add custom fonts to your application, add a fonts section here, 46 | # in this "flutter" section. Each entry in this list should have a 47 | # "family" key with the font family name, and a "fonts" key with a 48 | # list giving the asset and other descriptors for the font. For 49 | # example: 50 | # fonts: 51 | # - family: Schyler 52 | # fonts: 53 | # - asset: fonts/Schyler-Regular.ttf 54 | # - asset: fonts/Schyler-Italic.ttf 55 | # style: italic 56 | # - family: Trajan Pro 57 | # fonts: 58 | # - asset: fonts/TrajanPro.ttf 59 | # - asset: fonts/TrajanPro_Bold.ttf 60 | # weight: 700 61 | # 62 | # For details regarding fonts from package dependencies, 63 | # see https://flutter.dev/custom-fonts/#from-packages 64 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | 4 | import 'package:flutter/services.dart'; 5 | import 'package:flutter_tts_improved/flutter_tts_improved.dart'; 6 | 7 | void main() => runApp(MyApp()); 8 | 9 | class MyApp extends StatefulWidget { 10 | @override 11 | _MyAppState createState() => _MyAppState(); 12 | } 13 | 14 | class _MyAppState extends State { 15 | String _platformVersion = 'Unknown'; 16 | FlutterTtsImproved tts = FlutterTtsImproved(); 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | initPlatformState(); 22 | } 23 | 24 | // Platform messages are asynchronous, so we initialize in an async method. 25 | Future initPlatformState() async { 26 | // If the widget was removed from the tree while the asynchronous platform 27 | // message was in flight, we want to discard the reply rather than calling 28 | // setState to update our non-existent appearance. 29 | if (!mounted) return; 30 | 31 | print('VOICES: ${await tts.getVoices}'); 32 | print('LANGUAGES: ${await tts.getLanguages}'); 33 | 34 | tts.setProgressHandler((String words, int start, int end, String word) { 35 | setState(() { 36 | _platformVersion = word; 37 | }); 38 | print('PROGRESS: $word => $start - $end'); 39 | }); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return MaterialApp( 45 | home: Scaffold( 46 | appBar: AppBar( 47 | title: const Text('Plugin example app'), 48 | ), 49 | body: Center( 50 | child: Column( 51 | mainAxisAlignment: MainAxisAlignment.center, 52 | crossAxisAlignment: CrossAxisAlignment.center, 53 | children: [ 54 | Padding( 55 | padding: const EdgeInsets.only(bottom: 20), 56 | child: RaisedButton( 57 | onPressed: () { 58 | tts.speak('say something that we can debug please'); 59 | }, 60 | child: Text('Say Something...'), 61 | ), 62 | ), 63 | Text('Running on: $_platformVersion\n'), 64 | ], 65 | ), 66 | ), 67 | ), 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Using a CDN with CocoaPods 1.7.2 or later can save a lot of time on pod installation, but it's experimental rather than the default. 2 | # source 'https://cdn.cocoapods.org/' 3 | 4 | # Uncomment this line to define a global platform for your project 5 | # platform :ios, '9.0' 6 | 7 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 8 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 9 | 10 | project 'Runner', { 11 | 'Debug' => :debug, 12 | 'Profile' => :release, 13 | 'Release' => :release, 14 | } 15 | 16 | def parse_KV_file(file, separator='=') 17 | file_abs_path = File.expand_path(file) 18 | if !File.exists? file_abs_path 19 | return []; 20 | end 21 | pods_ary = [] 22 | skip_line_start_symbols = ["#", "/"] 23 | File.foreach(file_abs_path) { |line| 24 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } 25 | plugin = line.split(pattern=separator) 26 | if plugin.length == 2 27 | podname = plugin[0].strip() 28 | path = plugin[1].strip() 29 | podpath = File.expand_path("#{path}", file_abs_path) 30 | pods_ary.push({:name => podname, :path => podpath}); 31 | else 32 | puts "Invalid plugin specification: #{line}" 33 | end 34 | } 35 | return pods_ary 36 | end 37 | 38 | target 'Runner' do 39 | use_frameworks! 40 | 41 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 42 | # referring to absolute paths on developers' machines. 43 | system('rm -rf .symlinks') 44 | system('mkdir -p .symlinks/plugins') 45 | 46 | # Flutter Pods 47 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 48 | if generated_xcode_build_settings.empty? 49 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." 50 | end 51 | generated_xcode_build_settings.map { |p| 52 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 53 | symlink = File.join('.symlinks', 'flutter') 54 | File.symlink(File.dirname(p[:path]), symlink) 55 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 56 | end 57 | } 58 | 59 | # Plugin Pods 60 | plugin_pods = parse_KV_file('../.flutter-plugins') 61 | plugin_pods.map { |p| 62 | symlink = File.join('.symlinks', 'plugins', p[:name]) 63 | File.symlink(p[:path], symlink) 64 | pod p[:name], :path => File.join(symlink, 'ios') 65 | } 66 | end 67 | 68 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 69 | install! 'cocoapods', :disable_input_output_paths => true 70 | 71 | post_install do |installer| 72 | installer.pods_project.targets.each do |target| 73 | target.build_configurations.each do |config| 74 | config.build_settings['ENABLE_BITCODE'] = 'NO' 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.3.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.5" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | flutter: 33 | dependency: "direct main" 34 | description: flutter 35 | source: sdk 36 | version: "0.0.0" 37 | flutter_test: 38 | dependency: "direct dev" 39 | description: flutter 40 | source: sdk 41 | version: "0.0.0" 42 | matcher: 43 | dependency: transitive 44 | description: 45 | name: matcher 46 | url: "https://pub.dartlang.org" 47 | source: hosted 48 | version: "0.12.5" 49 | meta: 50 | dependency: transitive 51 | description: 52 | name: meta 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "1.1.7" 56 | path: 57 | dependency: transitive 58 | description: 59 | name: path 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "1.6.4" 63 | pedantic: 64 | dependency: transitive 65 | description: 66 | name: pedantic 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.8.0+1" 70 | quiver: 71 | dependency: transitive 72 | description: 73 | name: quiver 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "2.0.5" 77 | sky_engine: 78 | dependency: transitive 79 | description: flutter 80 | source: sdk 81 | version: "0.0.99" 82 | source_span: 83 | dependency: transitive 84 | description: 85 | name: source_span 86 | url: "https://pub.dartlang.org" 87 | source: hosted 88 | version: "1.5.5" 89 | stack_trace: 90 | dependency: transitive 91 | description: 92 | name: stack_trace 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "1.9.3" 96 | stream_channel: 97 | dependency: transitive 98 | description: 99 | name: stream_channel 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "2.0.0" 103 | string_scanner: 104 | dependency: transitive 105 | description: 106 | name: string_scanner 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.0.5" 110 | term_glyph: 111 | dependency: transitive 112 | description: 113 | name: term_glyph 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.1.0" 117 | test_api: 118 | dependency: transitive 119 | description: 120 | name: test_api 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.2.5" 124 | typed_data: 125 | dependency: transitive 126 | description: 127 | name: typed_data 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.6" 131 | vector_math: 132 | dependency: transitive 133 | description: 134 | name: vector_math 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "2.0.8" 138 | sdks: 139 | dart: ">=2.2.2 <3.0.0" 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Text To Speech Improved 2 | 3 | The `flutter_tts` plugin (https://github.com/dlutton/flutter_tts) is GREAT! Thanks [@dlutton](https://github.com/dlutton/) for all your hard work on getting it up and running. Now it is time to improve it by allowing for the Utterances API to report the 'progress' of the speech of the Utterance. This is relatively new for Android, only introduced in Android 26. It has been around on iOS for quite some time though, back around iOS 7.0. 4 | 5 | My goal with this plugin is to allow everyone in flutter to track where the speech is currently at. This can be used to print words on the screen as they are spoken, highlight words of a paragraph as they are uttered, for timing how long each word takes to say at a given speed, or really any other weird reason you may need it. This API is powerful, and I know people are asking for it, and there is simply not a plugin yet that covers it. Surprise! Now there is. You are welcome. 6 | 7 | ## Features 8 | 9 | - [x] Android & iOS 10 | - [x] speak 11 | - [x] stop 12 | - [x] get languages 13 | - [x] set language 14 | - [x] is language available 15 | - [x] set speech rate 16 | - [x] set speech volume 17 | - [x] set speech pitch 18 | - [x] get voices 19 | - [x] set voice 20 | - [x] #NEW track what word is currently being said (on all iOS 7+ and Android 26+) 21 | - [x] Android 22 | - [x] set Silence 23 | 24 | ## Usage 25 | 26 | ## Android 27 | 28 | Change the minimum Android sdk version to 21 (or higher) in your `android/app/build.gradle` file. 29 | 30 | ```java 31 | minSdkVersion 21 32 | ``` 33 | 34 | ## iOS 35 | 36 | There's a known issue with integrating plugins that use Swift into a Flutter project created with the Objective-C template. [Flutter#16049](https://github.com/flutter/flutter/issues/16049) 37 | 38 | [Example](https://github.com/loushou/flutter_tts_improved/blob/master/example/lib/main.dart) 39 | 40 | To use this plugin : 41 | 42 | - add the dependency to your [pubspec.yaml](https://github.com/loushou/flutter_tts_improved/blob/master/example/pubspec.yaml) file. 43 | 44 | ```yaml 45 | dependencies: 46 | flutter: 47 | sdk: flutter 48 | flutter_tts_improved: 49 | ``` 50 | 51 | - instantiate a FlutterTtsImproved instance 52 | 53 | ```dart 54 | FlutterTtsImproved tts = new FlutterTtsImproved(); 55 | ``` 56 | 57 | ### speak, stop, getLanguages, setLanguage, setSpeechRate, setVolume, setPitch, isLanguageAvailable 58 | 59 | ```dart 60 | Future _speak() async{ 61 | var result = await tts.speak("Hello World"); 62 | if (result == 1) setState(() => ttsState = TtsState.playing); 63 | } 64 | 65 | Future _stop() async{ 66 | var result = await tts.stop(); 67 | if (result == 1) setState(() => ttsState = TtsState.stopped); 68 | } 69 | 70 | List languages = await tts.getLanguages; 71 | 72 | await tts.setLanguage("en-US"); 73 | 74 | await tts.setSpeechRate(1.0); 75 | 76 | await tts.setVolume(1.0); 77 | 78 | await tts.setPitch(1.0); 79 | 80 | await tts.isLanguageAvailable("en-US"); 81 | ``` 82 | 83 | ### Listening for platform calls 84 | 85 | ```dart 86 | // #NEW 87 | tts.setProgressHandler((String fullPhrase, int wordOffset, int endOfWordOffset, String currentWord) { 88 | setState(() { 89 | _wordToDisplay = currentWord; 90 | }); 91 | }); 92 | 93 | tts.setStartHandler(() { 94 | setState(() { 95 | ttsState = TtsState.playing; 96 | }); 97 | }); 98 | 99 | tts.setCompletionHandler(() { 100 | setState(() { 101 | ttsState = TtsState.stopped; 102 | }); 103 | }); 104 | 105 | tts.setErrorHandler((msg) { 106 | setState(() { 107 | ttsState = TtsState.stopped; 108 | }); 109 | }); 110 | ``` 111 | 112 | ## Getting Started 113 | 114 | For help getting started with Flutter, view our online 115 | [documentation](https://flutter.io/). 116 | 117 | For help on editing plugin code, view the [documentation](https://flutter.io/platform-plugins/#edit-code). 118 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.3.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.5" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | cupertino_icons: 33 | dependency: "direct main" 34 | description: 35 | name: cupertino_icons 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "0.1.3" 39 | flutter: 40 | dependency: "direct main" 41 | description: flutter 42 | source: sdk 43 | version: "0.0.0" 44 | flutter_test: 45 | dependency: "direct dev" 46 | description: flutter 47 | source: sdk 48 | version: "0.0.0" 49 | flutter_tts_improved: 50 | dependency: "direct dev" 51 | description: 52 | path: ".." 53 | relative: true 54 | source: path 55 | version: "0.0.2" 56 | matcher: 57 | dependency: transitive 58 | description: 59 | name: matcher 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "0.12.5" 63 | meta: 64 | dependency: transitive 65 | description: 66 | name: meta 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.1.7" 70 | path: 71 | dependency: transitive 72 | description: 73 | name: path 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.6.4" 77 | pedantic: 78 | dependency: transitive 79 | description: 80 | name: pedantic 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.8.0+1" 84 | quiver: 85 | dependency: transitive 86 | description: 87 | name: quiver 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "2.0.5" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.5.5" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.9.3" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.0.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.0.5" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.2.5" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.1.6" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.0.8" 152 | sdks: 153 | dart: ">=2.2.2 <3.0.0" 154 | -------------------------------------------------------------------------------- /lib/flutter_tts_improved.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/services.dart'; 5 | 6 | typedef ErrorHandler = void Function(dynamic message); 7 | typedef FlutterTTSImprovedProgressHandler = void Function( 8 | String, int, int, String); 9 | 10 | // Provides Platform specific TTS services (Android: TextToSpeech, IOS: AVSpeechSynthesizer) 11 | class FlutterTtsImproved { 12 | FlutterTtsImproved() { 13 | _channel.setMethodCallHandler(platformCallHandler); 14 | } 15 | 16 | static const MethodChannel _channel = MethodChannel('flutter_tts_improved'); 17 | 18 | VoidCallback initHandler; 19 | VoidCallback startHandler; 20 | VoidCallback completionHandler; 21 | FlutterTTSImprovedProgressHandler progressHandler; 22 | ErrorHandler errorHandler; 23 | 24 | /// [Future] which invokes the platform specific method for speaking 25 | Future speak(String text) => 26 | _channel.invokeMethod('speak', text); 27 | 28 | /// [Future] which invokes the platform specific method for setLanguage 29 | Future setLanguage(String language) => 30 | _channel.invokeMethod('setLanguage', language); 31 | 32 | /// [Future] which invokes the platform specific method for setSpeechRate 33 | /// Allowed values are in the range from 0.0 (silent) to 1.0 (loudest) 34 | Future setSpeechRate(double rate) => 35 | _channel.invokeMethod('setSpeechRate', rate); 36 | 37 | /// [Future] which invokes the platform specific method for setVolume 38 | /// Allowed values are in the range from 0.0 (silent) to 1.0 (loudest) 39 | Future setVolume(double volume) => 40 | _channel.invokeMethod('setVolume', volume); 41 | 42 | /// [Future] which invokes the platform specific method for setPitch 43 | /// 1.0 is default and ranges from .5 to 2.0 44 | Future setPitch(double pitch) => 45 | _channel.invokeMethod('setPitch', pitch); 46 | 47 | /// [Future] which invokes the platform specific method for setVoice 48 | /// ***Android supported only*** 49 | Future setVoice(String voice) => 50 | _channel.invokeMethod('setVoice', voice); 51 | 52 | /// [Future] which invokes the platform specific method for stop 53 | Future stop() => _channel.invokeMethod('stop'); 54 | 55 | /// [Future] which invokes the platform specific method for getLanguages 56 | /// Android issues with API 21 & 22 57 | /// Returns a list of available languages 58 | Future> get getLanguages async { 59 | final List languages = 60 | List.from(await _channel.invokeMethod('getLanguages')); 61 | return languages; 62 | } 63 | 64 | /// [Future] which invokes the platform specific method for getVoices 65 | /// ***Android supported only *** 66 | /// Returns a `List` of voice names 67 | Future get getVoices async { 68 | final List voices = 69 | List.from(await _channel.invokeMethod('getVoices')); 70 | return voices; 71 | } 72 | 73 | /// [Future] which invokes the platform specific method for isLanguageAvailable 74 | /// Returns `true` or `false` 75 | Future isLanguageAvailable(String language) => 76 | _channel.invokeMethod( 77 | 'isLanguageAvailable', {'language': language}); 78 | 79 | /// [Future] which invokes the platform specific method for setSilence 80 | /// 0 means start the utterance immediately. If the value is greater than zero a silence period in milliseconds is set according to the parameter 81 | Future setSilence(int timems) => 82 | _channel.invokeMethod('setSilence', timems ?? 0); 83 | 84 | void setStartHandler(VoidCallback callback) { 85 | startHandler = callback; 86 | } 87 | 88 | void setCompletionHandler(VoidCallback callback) { 89 | completionHandler = callback; 90 | } 91 | 92 | void setProgressHandler(FlutterTTSImprovedProgressHandler callback) { 93 | progressHandler = callback; 94 | } 95 | 96 | void setErrorHandler(ErrorHandler handler) { 97 | errorHandler = handler; 98 | } 99 | 100 | void ttsInitHandler(VoidCallback handler) { 101 | initHandler = handler; 102 | } 103 | 104 | /// Platform listeners 105 | Future platformCallHandler(MethodCall call) async { 106 | switch (call.method) { 107 | case 'tts.init': 108 | if (initHandler != null) { 109 | initHandler(); 110 | } 111 | break; 112 | case 'speak.onStart': 113 | if (startHandler != null) { 114 | startHandler(); 115 | } 116 | break; 117 | case 'speak.onComplete': 118 | if (completionHandler != null) { 119 | completionHandler(); 120 | } 121 | break; 122 | case 'speak.onProgress': 123 | if (progressHandler != null) { 124 | final Map args = call.arguments; 125 | progressHandler( 126 | args['string'].toString(), 127 | int.parse(args['start']), 128 | int.parse(args['end']), 129 | args['word'].toString(), 130 | ); 131 | } 132 | break; 133 | case 'speak.onError': 134 | if (errorHandler != null) { 135 | errorHandler(call.arguments); 136 | } 137 | break; 138 | default: 139 | print('Unknowm method ${call.method}'); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /ios/Classes/SwiftFlutterTtsImprovedPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import AVFoundation 4 | 5 | public class SwiftFlutterTtsImprovedPlugin: NSObject, FlutterPlugin, AVSpeechSynthesizerDelegate { 6 | let synthesizer = AVSpeechSynthesizer() 7 | var language: String = AVSpeechSynthesisVoice.currentLanguageCode() 8 | var rate: Float = AVSpeechUtteranceDefaultSpeechRate 9 | var languages = Set() 10 | var volume: Float = 1.0 11 | var pitch: Float = 1.0 12 | var voice: AVSpeechSynthesisVoice? 13 | 14 | var channel = FlutterMethodChannel() 15 | 16 | init(channel: FlutterMethodChannel) { 17 | super.init() 18 | self.channel = channel 19 | synthesizer.delegate = self 20 | setLanguages() 21 | 22 | // Allow audio playback when the Ring/Silent switch is set to silent 23 | do { 24 | try AVAudioSession.sharedInstance().setCategory(.playback) 25 | try AVAudioSession.sharedInstance().setActive(true) 26 | } catch { 27 | print(error) 28 | } 29 | } 30 | 31 | private func setLanguages() { 32 | for voice in AVSpeechSynthesisVoice.speechVoices(){ 33 | self.languages.insert(voice.language) 34 | } 35 | } 36 | 37 | public static func register(with registrar: FlutterPluginRegistrar) { 38 | let channel = FlutterMethodChannel(name: "flutter_tts_improved", binaryMessenger: registrar.messenger()) 39 | let instance = SwiftFlutterTtsImprovedPlugin(channel: channel) 40 | registrar.addMethodCallDelegate(instance, channel: channel) 41 | } 42 | 43 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { 44 | switch call.method { 45 | case "speak": 46 | let text: String = call.arguments as! String 47 | self.speak(text: text) 48 | result(1) 49 | break 50 | case "setLanguage": 51 | let language: String = call.arguments as! String 52 | self.setLanguage(language: language, result: result) 53 | break 54 | case "setSpeechRate": 55 | let rate: Double = call.arguments as! Double 56 | self.setRate(rate: Float(rate)) 57 | result(1) 58 | break 59 | case "setVolume": 60 | let volume: Double = call.arguments as! Double 61 | self.setVolume(volume: Float(volume), result: result) 62 | break 63 | case "setPitch": 64 | let pitch: Double = call.arguments as! Double 65 | self.setPitch(pitch: Float(pitch), result: result) 66 | break 67 | case "stop": 68 | self.stop() 69 | result(1) 70 | break 71 | case "getLanguages": 72 | self.getLanguages(result: result) 73 | break 74 | case "isLanguageAvailable": 75 | let arg: Dictionary = call.arguments as! Dictionary 76 | self.isLanguageAvailable(language: arg["language"]! as String, result: result) 77 | break 78 | case "getVoices": 79 | self.getVoices(result: result) 80 | break 81 | case "setVoice": 82 | let voiceName = call.arguments as! String 83 | self.setVoice(voiceName: voiceName, result: result) 84 | break 85 | default: 86 | result(FlutterMethodNotImplemented) 87 | } 88 | } 89 | 90 | private func speak(text: String) { 91 | let utterance = AVSpeechUtterance(string: text) 92 | if self.voice != nil { 93 | utterance.voice = self.voice! 94 | } else { 95 | utterance.voice = AVSpeechSynthesisVoice(language: self.language) 96 | } 97 | utterance.rate = self.rate 98 | utterance.volume = self.volume 99 | utterance.pitchMultiplier = self.pitch 100 | 101 | self.synthesizer.speak(utterance) 102 | } 103 | 104 | private func setLanguage(language: String, result: FlutterResult) { 105 | if !(self.languages.contains(language)) { 106 | result(0) 107 | } else { 108 | self.language = language 109 | self.voice = nil 110 | result(1) 111 | } 112 | } 113 | 114 | private func setRate(rate: Float) { 115 | self.rate = rate 116 | } 117 | 118 | private func setVolume(volume: Float, result: FlutterResult) { 119 | if (volume >= 0.0 && volume <= 1.0) { 120 | self.volume = volume 121 | result(1) 122 | } else { 123 | result(0) 124 | } 125 | } 126 | 127 | private func setPitch(pitch: Float, result: FlutterResult) { 128 | if (volume >= 0.5 && volume <= 2.0) { 129 | self.pitch = pitch 130 | result(1) 131 | } else { 132 | result(0) 133 | } 134 | } 135 | 136 | private func stop() { 137 | self.synthesizer.stopSpeaking(at: AVSpeechBoundary.immediate) 138 | } 139 | 140 | private func getLanguages(result: FlutterResult) { 141 | result(Array(self.languages)) 142 | } 143 | 144 | private func isLanguageAvailable(language: String, result: FlutterResult) { 145 | var isAvailable: Bool = false 146 | if (self.languages.contains(language)) { 147 | isAvailable = true 148 | } 149 | result(isAvailable); 150 | } 151 | 152 | private func getVoices(result: FlutterResult) { 153 | if #available(iOS 9.0, *) { 154 | let voices = NSMutableArray() 155 | for voice in AVSpeechSynthesisVoice.speechVoices() { 156 | voices.add(voice.name) 157 | } 158 | result(voices) 159 | } else { 160 | // Since voice selection is not supported below iOS 9, make voice getter and setter 161 | // have the same bahavior as language selection. 162 | getLanguages(result: result) 163 | } 164 | } 165 | 166 | private func setVoice(voiceName: String, result: FlutterResult) { 167 | if #available(iOS 9.0, *) { 168 | if let voice = AVSpeechSynthesisVoice.speechVoices().first(where: { $0.name == voiceName }) { 169 | self.voice = voice 170 | self.language = voice.language 171 | result(1) 172 | return 173 | } 174 | result(0) 175 | } else { 176 | setLanguage(language: voiceName, result: result) 177 | } 178 | } 179 | 180 | public func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) { 181 | self.channel.invokeMethod("speak.onComplete", arguments: nil) 182 | } 183 | 184 | public func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) { 185 | self.channel.invokeMethod("speak.onStart", arguments: nil) 186 | } 187 | 188 | public func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) { 189 | let nsWord = utterance.speechString as NSString 190 | let data: [String:String] = [ 191 | "string": utterance.speechString, 192 | "start": String(characterRange.location), 193 | "end": String(characterRange.location + characterRange.length), 194 | "word": nsWord.substring(with: characterRange) 195 | ] 196 | self.channel.invokeMethod("speak.onProgress", arguments: data) 197 | } 198 | } 199 | 200 | // Helper function inserted by Swift 4.2 migrator. 201 | fileprivate func convertFromAVAudioSessionCategory(_ input: AVAudioSession.Category) -> String { 202 | return input.rawValue 203 | } 204 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Specify analysis options. 2 | # 3 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 4 | # See: https://github.com/dart-lang/linter/issues/288 5 | # 6 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 7 | # See the configuration guide for more 8 | # https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer 9 | # 10 | # There are other similar analysis options files in the flutter repos, 11 | # which should be kept in sync with this file: 12 | # 13 | # - analysis_options.yaml (this file) 14 | # - packages/flutter/lib/analysis_options_user.yaml 15 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 16 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 17 | # 18 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 19 | # Android Studio, and the `flutter analyze` command. 20 | 21 | analyzer: 22 | strong-mode: 23 | implicit-dynamic: false 24 | errors: 25 | # treat missing required parameters as a warning (not a hint) 26 | missing_required_param: warning 27 | # treat missing returns as a warning (not a hint) 28 | missing_return: warning 29 | # allow having TODOs in the code 30 | todo: ignore 31 | # Ignore analyzer hints for updating pubspecs when using Future or 32 | # Stream and not importing dart:async 33 | # Please see https://github.com/flutter/flutter/pull/24528 for details. 34 | sdk_version_async_exported_from_core: ignore 35 | exclude: 36 | - 'bin/cache/**' 37 | # the following two are relative to the stocks example and the flutter package respectively 38 | # see https://github.com/dart-lang/sdk/issues/28463 39 | - 'lib/i18n/stock_messages_*.dart' 40 | - 'lib/src/http/**' 41 | 42 | linter: 43 | rules: 44 | # these rules are documented on and in the same order as 45 | # the Dart Lint rules page to make maintenance easier 46 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 47 | - always_declare_return_types 48 | - always_put_control_body_on_new_line 49 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 50 | - always_require_non_null_named_parameters 51 | - always_specify_types 52 | - annotate_overrides 53 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 54 | - avoid_as 55 | # - avoid_bool_literals_in_conditional_expressions # not yet tested 56 | # - avoid_catches_without_on_clauses # we do this commonly 57 | # - avoid_catching_errors # we do this commonly 58 | - avoid_classes_with_only_static_members 59 | # - avoid_double_and_int_checks # only useful when targeting JS runtime 60 | - avoid_empty_else 61 | - avoid_field_initializers_in_const_classes 62 | - avoid_function_literals_in_foreach_calls 63 | # - avoid_implementing_value_types # not yet tested 64 | - avoid_init_to_null 65 | # - avoid_js_rounded_ints # only useful when targeting JS runtime 66 | - avoid_null_checks_in_equality_operators 67 | # - avoid_positional_boolean_parameters # not yet tested 68 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 69 | - avoid_relative_lib_imports 70 | - avoid_renaming_method_parameters 71 | - avoid_return_types_on_setters 72 | # - avoid_returning_null # there are plenty of valid reasons to return null 73 | # - avoid_returning_null_for_future # not yet tested 74 | - avoid_returning_null_for_void 75 | # - avoid_returning_this # there are plenty of valid reasons to return this 76 | # - avoid_setters_without_getters # not yet tested 77 | # - avoid_shadowing_type_parameters # not yet tested 78 | # - avoid_single_cascade_in_expression_statements # not yet tested 79 | - avoid_slow_async_io 80 | - avoid_types_as_parameter_names 81 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 82 | - avoid_unused_constructor_parameters 83 | - avoid_void_async 84 | - await_only_futures 85 | - camel_case_types 86 | - cancel_subscriptions 87 | # - cascade_invocations # not yet tested 88 | # - close_sinks # not reliable enough 89 | # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 90 | # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 91 | - control_flow_in_finally 92 | # - curly_braces_in_flow_control_structures # not yet tested 93 | - directives_ordering 94 | - empty_catches 95 | - empty_constructor_bodies 96 | - empty_statements 97 | # - file_names # not yet tested 98 | - flutter_style_todos 99 | - hash_and_equals 100 | - implementation_imports 101 | # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 102 | - iterable_contains_unrelated_type 103 | # - join_return_with_assignment # not yet tested 104 | - library_names 105 | - library_prefixes 106 | # - lines_longer_than_80_chars # not yet tested 107 | - list_remove_unrelated_type 108 | # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 109 | - no_adjacent_strings_in_list 110 | - no_duplicate_case_values 111 | - non_constant_identifier_names 112 | # - null_closures # not yet tested 113 | # - omit_local_variable_types # opposite of always_specify_types 114 | # - one_member_abstracts # too many false positives 115 | # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 116 | - overridden_fields 117 | - package_api_docs 118 | - package_names 119 | - package_prefixed_library_names 120 | # - parameter_assignments # we do this commonly 121 | - prefer_adjacent_string_concatenation 122 | - prefer_asserts_in_initializer_lists 123 | - prefer_collection_literals 124 | - prefer_conditional_assignment 125 | - prefer_const_constructors 126 | - prefer_const_constructors_in_immutables 127 | - prefer_const_declarations 128 | - prefer_const_literals_to_create_immutables 129 | # - prefer_constructors_over_static_methods # not yet tested 130 | - prefer_contains 131 | - prefer_equal_for_default_values 132 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 133 | - prefer_final_fields 134 | - prefer_final_locals 135 | - prefer_foreach 136 | # - prefer_function_declarations_over_variables # not yet tested 137 | - prefer_generic_function_type_aliases 138 | - prefer_initializing_formals 139 | # - prefer_int_literals # not yet tested 140 | # - prefer_interpolation_to_compose_strings # not yet tested 141 | - prefer_is_empty 142 | - prefer_is_not_empty 143 | - prefer_iterable_whereType 144 | # - prefer_mixin # https://github.com/dart-lang/language/issues/32 145 | - prefer_single_quotes 146 | - prefer_typing_uninitialized_variables 147 | - prefer_void_to_null 148 | # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml 149 | - recursive_getters 150 | - slash_for_doc_comments 151 | - sort_constructors_first 152 | - sort_pub_dependencies 153 | - sort_unnamed_constructors_first 154 | # - super_goes_last # no longer needed w/ Dart 2 155 | - test_types_in_equals 156 | - throw_in_finally 157 | # - type_annotate_public_apis # subset of always_specify_types 158 | - type_init_formals 159 | # - unawaited_futures # too many false positives 160 | # - unnecessary_await_in_return # not yet tested 161 | - unnecessary_brace_in_string_interps 162 | - unnecessary_const 163 | - unnecessary_getters_setters 164 | # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 165 | - unnecessary_new 166 | - unnecessary_null_aware_assignments 167 | - unnecessary_null_in_if_null_operators 168 | - unnecessary_overrides 169 | - unnecessary_parenthesis 170 | - unnecessary_statements 171 | - unnecessary_this 172 | - unrelated_type_equality_checks 173 | # - use_function_type_syntax_for_parameters # not yet tested 174 | - use_rethrow_when_possible 175 | # - use_setters_to_change_properties # not yet tested 176 | # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 177 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 178 | - valid_regexps 179 | # - void_checks # not yet tested 180 | -------------------------------------------------------------------------------- /android/src/main/java/com/rdygo/flutter_tts_improved/FlutterTtsImprovedPlugin.java: -------------------------------------------------------------------------------- 1 | package com.rdygo.flutter_tts_improved; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | import android.speech.tts.TextToSpeech; 9 | import android.speech.tts.UtteranceProgressListener; 10 | import android.speech.tts.Voice; 11 | import android.util.Log; 12 | 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.Locale; 16 | import java.util.UUID; 17 | 18 | import io.flutter.plugin.common.MethodCall; 19 | import io.flutter.plugin.common.MethodChannel; 20 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 21 | import io.flutter.plugin.common.MethodChannel.Result; 22 | import io.flutter.plugin.common.PluginRegistry.Registrar; 23 | 24 | /** 25 | * FlutterTtsPlugin 26 | */ 27 | public class FlutterTtsImprovedPlugin implements MethodCallHandler { 28 | private final Handler handler; 29 | private final MethodChannel channel; 30 | private TextToSpeech tts; 31 | private final String tag = "TTS"; 32 | private final String googleTtsEngine = "com.google.android.tts"; 33 | String uuid; 34 | Bundle bundle; 35 | private int silencems; 36 | private static final String SILENCE_PREFIX = "SIL_"; 37 | private final HashMap utterances = new HashMap<>(); 38 | 39 | /** 40 | * Plugin registration. 41 | */ 42 | private FlutterTtsImprovedPlugin(Context context, MethodChannel channel) { 43 | this.channel = channel; 44 | this.channel.setMethodCallHandler(this); 45 | 46 | handler = new Handler(Looper.getMainLooper()); 47 | bundle = new Bundle(); 48 | tts = new TextToSpeech(context.getApplicationContext(), onInitListener, googleTtsEngine); 49 | } 50 | 51 | private UtteranceProgressListener utteranceProgressListener = 52 | new UtteranceProgressListener() { 53 | @Override 54 | public void onStart(String utteranceId) { 55 | invokeMethod("speak.onStart", true); 56 | if (Build.VERSION.SDK_INT < 26) { 57 | this.triggerProgress(utteranceId, 0, utterances.get(utteranceId).length()); 58 | } 59 | } 60 | 61 | @Override 62 | public void onDone(String utteranceId) { 63 | if (utteranceId != null && utteranceId.startsWith(SILENCE_PREFIX)) 64 | return; 65 | invokeMethod("speak.onComplete", true); 66 | utterances.remove(utteranceId); 67 | } 68 | 69 | private void triggerProgress(String utteranceId, int startAt, int endAt) { 70 | final String words = utterances.get(utteranceId); 71 | final HashMap data = new HashMap<>(); 72 | data.put("string", words); 73 | data.put("start", Integer.toString(startAt)); 74 | data.put("end", Integer.toString(endAt)); 75 | data.put("word", words.substring(startAt, endAt)); 76 | invokeMethod("speak.onProgress", data); 77 | } 78 | 79 | // only valid on android 26 and higher 80 | @Override 81 | public void onRangeStart(String utteranceId, int startAt, int endAt, int frame) { 82 | super.onRangeStart(utteranceId, startAt, endAt, frame); 83 | this.triggerProgress(utteranceId, startAt, endAt); 84 | } 85 | 86 | @Override 87 | @Deprecated 88 | public void onError(String utteranceId) { 89 | invokeMethod("speak.onError", "Error from TextToSpeech"); 90 | } 91 | 92 | @Override 93 | public void onError(String utteranceId, int errorCode) { 94 | invokeMethod("speak.onError", "Error from TextToSpeech - " + errorCode); 95 | } 96 | }; 97 | 98 | private TextToSpeech.OnInitListener onInitListener = 99 | new TextToSpeech.OnInitListener() { 100 | @Override 101 | public void onInit(int status) { 102 | if (status == TextToSpeech.SUCCESS) { 103 | tts.setOnUtteranceProgressListener(utteranceProgressListener); 104 | invokeMethod("tts.init", true); 105 | 106 | try { 107 | Locale locale = tts.getDefaultVoice().getLocale(); 108 | if (isLanguageAvailable(locale)) { 109 | tts.setLanguage(locale); 110 | } 111 | } catch (NullPointerException | IllegalArgumentException e) { 112 | Log.e(tag, "getDefaultLocale: " + e.getMessage()); 113 | } 114 | } else { 115 | Log.e(tag, "Failed to initialize TextToSpeech"); 116 | } 117 | } 118 | }; 119 | 120 | public static void registerWith(Registrar registrar) { 121 | final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_tts_improved"); 122 | channel.setMethodCallHandler(new FlutterTtsImprovedPlugin(registrar.activeContext(), channel)); 123 | } 124 | 125 | @Override 126 | public void onMethodCall(MethodCall call, Result result) { 127 | if (call.method.equals("speak")) { 128 | String text = call.arguments.toString(); 129 | speak(text); 130 | result.success(1); 131 | } else if (call.method.equals("stop")) { 132 | stop(); 133 | result.success(1); 134 | } else if (call.method.equals("setSpeechRate")) { 135 | String rate = call.arguments.toString(); 136 | setSpeechRate(Float.parseFloat(rate)); 137 | result.success(1); 138 | } else if (call.method.equals("setVolume")) { 139 | String volume = call.arguments.toString(); 140 | setVolume(Float.parseFloat(volume), result); 141 | } else if (call.method.equals("setPitch")) { 142 | String pitch = call.arguments.toString(); 143 | setPitch(Float.parseFloat(pitch), result); 144 | } else if (call.method.equals("setLanguage")) { 145 | String language = call.arguments.toString(); 146 | setLanguage(language, result); 147 | } else if (call.method.equals("getLanguages")) { 148 | getLanguages(result); 149 | } else if (call.method.equals("getVoices")) { 150 | getVoices(result); 151 | } else if (call.method.equals("setVoice")) { 152 | String voice = call.arguments.toString(); 153 | setVoice(voice, result); 154 | } else if (call.method.equals("isLanguageAvailable")) { 155 | String language = ((HashMap) call.arguments()).get("language").toString(); 156 | Locale locale = Locale.forLanguageTag(language); 157 | result.success(isLanguageAvailable(locale)); 158 | } else if (call.method.equals("setSilence")) { 159 | String silencems = call.arguments.toString(); 160 | this.silencems = Integer.parseInt(silencems); 161 | } else { 162 | result.notImplemented(); 163 | } 164 | } 165 | 166 | void setSpeechRate(float rate) { 167 | tts.setSpeechRate(rate); 168 | } 169 | 170 | Boolean isLanguageAvailable(Locale locale) { 171 | return tts.isLanguageAvailable(locale) >= TextToSpeech.LANG_AVAILABLE; 172 | } 173 | 174 | void setLanguage(String language, Result result) { 175 | Locale locale = Locale.forLanguageTag(language); 176 | if (isLanguageAvailable(locale)) { 177 | tts.setLanguage(locale); 178 | result.success(1); 179 | } else { 180 | result.success(0); 181 | } 182 | } 183 | 184 | void setVoice(String voice, Result result) { 185 | for (Voice ttsVoice : tts.getVoices()) { 186 | if (ttsVoice.getName().equals(voice)) { 187 | tts.setVoice(ttsVoice); 188 | result.success(1); 189 | return; 190 | } 191 | } 192 | Log.d(tag, "Voice name not found: " + voice); 193 | result.success(0); 194 | } 195 | 196 | void setVolume(float volume, Result result) { 197 | if (volume >= 0.0F && volume <= 1.0F) { 198 | bundle.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, volume); 199 | result.success(1); 200 | } else { 201 | Log.d(tag, "Invalid volume " + volume + " value - Range is from 0.0 to 1.0"); 202 | result.success(0); 203 | } 204 | } 205 | 206 | void setPitch(float pitch, Result result) { 207 | if (pitch >= 0.5F && pitch <= 2.0F) { 208 | tts.setPitch(pitch); 209 | result.success(1); 210 | } else { 211 | Log.d(tag, "Invalid pitch " + pitch + " value - Range is from 0.5 to 2.0"); 212 | result.success(0); 213 | } 214 | } 215 | 216 | void getVoices(Result result) { 217 | ArrayList voices = new ArrayList<>(); 218 | try { 219 | for (Voice voice : tts.getVoices()) { 220 | voices.add(voice.getName()); 221 | } 222 | result.success(voices); 223 | } catch (NullPointerException e) { 224 | Log.d(tag, "getVoices: " + e.getMessage()); 225 | result.success(null); 226 | } 227 | } 228 | 229 | void getLanguages(Result result) { 230 | ArrayList locales = new ArrayList<>(); 231 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 232 | // While this method was introduced in API level 21, it seems that it 233 | // has not been implemented in the speech service side until API Level 23. 234 | for (Locale locale : tts.getAvailableLanguages()) { 235 | locales.add(locale.toLanguageTag()); 236 | } 237 | } else { 238 | for (Locale locale : Locale.getAvailableLocales()) { 239 | if (locale.getVariant().isEmpty() && isLanguageAvailable(locale)) { 240 | locales.add(locale.toLanguageTag()); 241 | } 242 | } 243 | } 244 | result.success(locales); 245 | } 246 | 247 | private void speak(String text) { 248 | uuid = UUID.randomUUID().toString(); 249 | utterances.put(uuid, text); 250 | if (silencems > 0) { 251 | tts.playSilentUtterance(silencems, TextToSpeech.QUEUE_FLUSH, SILENCE_PREFIX + uuid); 252 | tts.speak(text, TextToSpeech.QUEUE_ADD, bundle, uuid); 253 | } else { 254 | tts.speak(text, TextToSpeech.QUEUE_FLUSH, bundle, uuid); 255 | } 256 | } 257 | 258 | private void stop() { 259 | tts.stop(); 260 | } 261 | 262 | private void invokeMethod(final String method, final Object arguments) { 263 | handler.post(new Runnable() { 264 | @Override 265 | public void run() { 266 | channel.invokeMethod(method, arguments); 267 | } 268 | }); 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 18 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 19 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 20 | F470ED94F262E0132284B7AD /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5897AF5EFD5DB607E7DF00C /* Pods_Runner.framework */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = ""; 28 | dstSubfolderSpec = 10; 29 | files = ( 30 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 31 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 32 | ); 33 | name = "Embed Frameworks"; 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 40 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 41 | 18FF990F562979DC2ABC60C5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 45 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 48 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 49 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 50 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 52 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 53 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 54 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | B5897AF5EFD5DB607E7DF00C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | C1E893CBCD8193860E4C7636 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 57 | FFA707EEF1D855824DDCD901 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | F470ED94F262E0132284B7AD /* Pods_Runner.framework in Frameworks */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 81B026AA0AD92FB31699D931 /* Pods */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | C1E893CBCD8193860E4C7636 /* Pods-Runner.debug.xcconfig */, 78 | FFA707EEF1D855824DDCD901 /* Pods-Runner.release.xcconfig */, 79 | 18FF990F562979DC2ABC60C5 /* Pods-Runner.profile.xcconfig */, 80 | ); 81 | path = Pods; 82 | sourceTree = ""; 83 | }; 84 | 9740EEB11CF90186004384FC /* Flutter */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 3B80C3931E831B6300D905FE /* App.framework */, 88 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 89 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 90 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 91 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 92 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 93 | ); 94 | name = Flutter; 95 | sourceTree = ""; 96 | }; 97 | 97C146E51CF9000F007C117D = { 98 | isa = PBXGroup; 99 | children = ( 100 | 9740EEB11CF90186004384FC /* Flutter */, 101 | 97C146F01CF9000F007C117D /* Runner */, 102 | 97C146EF1CF9000F007C117D /* Products */, 103 | 81B026AA0AD92FB31699D931 /* Pods */, 104 | B8C1F8EC47BE6D94A8DC5773 /* Frameworks */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | 97C146EF1CF9000F007C117D /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 97C146EE1CF9000F007C117D /* Runner.app */, 112 | ); 113 | name = Products; 114 | sourceTree = ""; 115 | }; 116 | 97C146F01CF9000F007C117D /* Runner */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 120 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 121 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 122 | 97C147021CF9000F007C117D /* Info.plist */, 123 | 97C146F11CF9000F007C117D /* Supporting Files */, 124 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 125 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 126 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 127 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 128 | ); 129 | path = Runner; 130 | sourceTree = ""; 131 | }; 132 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | ); 136 | name = "Supporting Files"; 137 | sourceTree = ""; 138 | }; 139 | B8C1F8EC47BE6D94A8DC5773 /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | B5897AF5EFD5DB607E7DF00C /* Pods_Runner.framework */, 143 | ); 144 | name = Frameworks; 145 | sourceTree = ""; 146 | }; 147 | /* End PBXGroup section */ 148 | 149 | /* Begin PBXNativeTarget section */ 150 | 97C146ED1CF9000F007C117D /* Runner */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 153 | buildPhases = ( 154 | D2233D95DB5F7161AADBF623 /* [CP] Check Pods Manifest.lock */, 155 | 9740EEB61CF901F6004384FC /* Run Script */, 156 | 97C146EA1CF9000F007C117D /* Sources */, 157 | 97C146EB1CF9000F007C117D /* Frameworks */, 158 | 97C146EC1CF9000F007C117D /* Resources */, 159 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 160 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 161 | BA807C0B8615FF7F16C5EB1D /* [CP] Embed Pods Frameworks */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | ); 167 | name = Runner; 168 | productName = Runner; 169 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | 97C146E61CF9000F007C117D /* Project object */ = { 176 | isa = PBXProject; 177 | attributes = { 178 | LastUpgradeCheck = 1100; 179 | ORGANIZATIONNAME = "The Chromium Authors"; 180 | TargetAttributes = { 181 | 97C146ED1CF9000F007C117D = { 182 | CreatedOnToolsVersion = 7.3.1; 183 | DevelopmentTeam = 49427B483J; 184 | LastSwiftMigration = 1100; 185 | }; 186 | }; 187 | }; 188 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 189 | compatibilityVersion = "Xcode 3.2"; 190 | developmentRegion = en; 191 | hasScannedForEncodings = 0; 192 | knownRegions = ( 193 | en, 194 | Base, 195 | ); 196 | mainGroup = 97C146E51CF9000F007C117D; 197 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 198 | projectDirPath = ""; 199 | projectRoot = ""; 200 | targets = ( 201 | 97C146ED1CF9000F007C117D /* Runner */, 202 | ); 203 | }; 204 | /* End PBXProject section */ 205 | 206 | /* Begin PBXResourcesBuildPhase section */ 207 | 97C146EC1CF9000F007C117D /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 212 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 213 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 214 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXResourcesBuildPhase section */ 219 | 220 | /* Begin PBXShellScriptBuildPhase section */ 221 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 222 | isa = PBXShellScriptBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | inputPaths = ( 227 | ); 228 | name = "Thin Binary"; 229 | outputPaths = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | shellPath = /bin/sh; 233 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 234 | }; 235 | 9740EEB61CF901F6004384FC /* Run Script */ = { 236 | isa = PBXShellScriptBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | ); 240 | inputPaths = ( 241 | ); 242 | name = "Run Script"; 243 | outputPaths = ( 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | shellPath = /bin/sh; 247 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 248 | }; 249 | BA807C0B8615FF7F16C5EB1D /* [CP] Embed Pods Frameworks */ = { 250 | isa = PBXShellScriptBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | inputPaths = ( 255 | ); 256 | name = "[CP] Embed Pods Frameworks"; 257 | outputPaths = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | shellPath = /bin/sh; 261 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 262 | showEnvVarsInLog = 0; 263 | }; 264 | D2233D95DB5F7161AADBF623 /* [CP] Check Pods Manifest.lock */ = { 265 | isa = PBXShellScriptBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | ); 269 | inputFileListPaths = ( 270 | ); 271 | inputPaths = ( 272 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 273 | "${PODS_ROOT}/Manifest.lock", 274 | ); 275 | name = "[CP] Check Pods Manifest.lock"; 276 | outputFileListPaths = ( 277 | ); 278 | outputPaths = ( 279 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | shellPath = /bin/sh; 283 | 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"; 284 | showEnvVarsInLog = 0; 285 | }; 286 | /* End PBXShellScriptBuildPhase section */ 287 | 288 | /* Begin PBXSourcesBuildPhase section */ 289 | 97C146EA1CF9000F007C117D /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 294 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXSourcesBuildPhase section */ 299 | 300 | /* Begin PBXVariantGroup section */ 301 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 302 | isa = PBXVariantGroup; 303 | children = ( 304 | 97C146FB1CF9000F007C117D /* Base */, 305 | ); 306 | name = Main.storyboard; 307 | sourceTree = ""; 308 | }; 309 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 310 | isa = PBXVariantGroup; 311 | children = ( 312 | 97C147001CF9000F007C117D /* Base */, 313 | ); 314 | name = LaunchScreen.storyboard; 315 | sourceTree = ""; 316 | }; 317 | /* End PBXVariantGroup section */ 318 | 319 | /* Begin XCBuildConfiguration section */ 320 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 321 | isa = XCBuildConfiguration; 322 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 323 | buildSettings = { 324 | ALWAYS_SEARCH_USER_PATHS = NO; 325 | CLANG_ANALYZER_NONNULL = YES; 326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 327 | CLANG_CXX_LIBRARY = "libc++"; 328 | CLANG_ENABLE_MODULES = YES; 329 | CLANG_ENABLE_OBJC_ARC = YES; 330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 331 | CLANG_WARN_BOOL_CONVERSION = YES; 332 | CLANG_WARN_COMMA = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 336 | CLANG_WARN_EMPTY_BODY = YES; 337 | CLANG_WARN_ENUM_CONVERSION = YES; 338 | CLANG_WARN_INFINITE_RECURSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 345 | CLANG_WARN_STRICT_PROTOTYPES = YES; 346 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 347 | CLANG_WARN_UNREACHABLE_CODE = YES; 348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 350 | COPY_PHASE_STRIP = NO; 351 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 352 | ENABLE_NS_ASSERTIONS = NO; 353 | ENABLE_STRICT_OBJC_MSGSEND = YES; 354 | GCC_C_LANGUAGE_STANDARD = gnu99; 355 | GCC_NO_COMMON_BLOCKS = YES; 356 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 357 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 358 | GCC_WARN_UNDECLARED_SELECTOR = YES; 359 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 360 | GCC_WARN_UNUSED_FUNCTION = YES; 361 | GCC_WARN_UNUSED_VARIABLE = YES; 362 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 363 | MTL_ENABLE_DEBUG_INFO = NO; 364 | SDKROOT = iphoneos; 365 | TARGETED_DEVICE_FAMILY = "1,2"; 366 | VALIDATE_PRODUCT = YES; 367 | }; 368 | name = Profile; 369 | }; 370 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 371 | isa = XCBuildConfiguration; 372 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 373 | buildSettings = { 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | CLANG_ENABLE_MODULES = YES; 376 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 377 | DEVELOPMENT_TEAM = 49427B483J; 378 | ENABLE_BITCODE = NO; 379 | FRAMEWORK_SEARCH_PATHS = ( 380 | "$(inherited)", 381 | "$(PROJECT_DIR)/Flutter", 382 | ); 383 | INFOPLIST_FILE = Runner/Info.plist; 384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 385 | LIBRARY_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "$(PROJECT_DIR)/Flutter", 388 | ); 389 | PRODUCT_BUNDLE_IDENTIFIER = com.rdygo.flutterTtsImprovedExample; 390 | PRODUCT_NAME = "$(TARGET_NAME)"; 391 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 392 | SWIFT_VERSION = 5.0; 393 | VERSIONING_SYSTEM = "apple-generic"; 394 | }; 395 | name = Profile; 396 | }; 397 | 97C147031CF9000F007C117D /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 400 | buildSettings = { 401 | ALWAYS_SEARCH_USER_PATHS = NO; 402 | CLANG_ANALYZER_NONNULL = YES; 403 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 404 | CLANG_CXX_LIBRARY = "libc++"; 405 | CLANG_ENABLE_MODULES = YES; 406 | CLANG_ENABLE_OBJC_ARC = YES; 407 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 408 | CLANG_WARN_BOOL_CONVERSION = YES; 409 | CLANG_WARN_COMMA = YES; 410 | CLANG_WARN_CONSTANT_CONVERSION = YES; 411 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 413 | CLANG_WARN_EMPTY_BODY = YES; 414 | CLANG_WARN_ENUM_CONVERSION = YES; 415 | CLANG_WARN_INFINITE_RECURSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 418 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 422 | CLANG_WARN_STRICT_PROTOTYPES = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = dwarf; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | ENABLE_TESTABILITY = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_DYNAMIC_NO_PIC = NO; 433 | GCC_NO_COMMON_BLOCKS = YES; 434 | GCC_OPTIMIZATION_LEVEL = 0; 435 | GCC_PREPROCESSOR_DEFINITIONS = ( 436 | "DEBUG=1", 437 | "$(inherited)", 438 | ); 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 446 | MTL_ENABLE_DEBUG_INFO = YES; 447 | ONLY_ACTIVE_ARCH = YES; 448 | SDKROOT = iphoneos; 449 | TARGETED_DEVICE_FAMILY = "1,2"; 450 | }; 451 | name = Debug; 452 | }; 453 | 97C147041CF9000F007C117D /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 456 | buildSettings = { 457 | ALWAYS_SEARCH_USER_PATHS = NO; 458 | CLANG_ANALYZER_NONNULL = YES; 459 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 460 | CLANG_CXX_LIBRARY = "libc++"; 461 | CLANG_ENABLE_MODULES = YES; 462 | CLANG_ENABLE_OBJC_ARC = YES; 463 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 464 | CLANG_WARN_BOOL_CONVERSION = YES; 465 | CLANG_WARN_COMMA = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 469 | CLANG_WARN_EMPTY_BODY = YES; 470 | CLANG_WARN_ENUM_CONVERSION = YES; 471 | CLANG_WARN_INFINITE_RECURSION = YES; 472 | CLANG_WARN_INT_CONVERSION = YES; 473 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 474 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 475 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 476 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 477 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 478 | CLANG_WARN_STRICT_PROTOTYPES = YES; 479 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 483 | COPY_PHASE_STRIP = NO; 484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 485 | ENABLE_NS_ASSERTIONS = NO; 486 | ENABLE_STRICT_OBJC_MSGSEND = YES; 487 | GCC_C_LANGUAGE_STANDARD = gnu99; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 496 | MTL_ENABLE_DEBUG_INFO = NO; 497 | SDKROOT = iphoneos; 498 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 499 | TARGETED_DEVICE_FAMILY = "1,2"; 500 | VALIDATE_PRODUCT = YES; 501 | }; 502 | name = Release; 503 | }; 504 | 97C147061CF9000F007C117D /* Debug */ = { 505 | isa = XCBuildConfiguration; 506 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 507 | buildSettings = { 508 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 509 | CLANG_ENABLE_MODULES = YES; 510 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 511 | DEVELOPMENT_TEAM = 49427B483J; 512 | ENABLE_BITCODE = NO; 513 | FRAMEWORK_SEARCH_PATHS = ( 514 | "$(inherited)", 515 | "$(PROJECT_DIR)/Flutter", 516 | ); 517 | INFOPLIST_FILE = Runner/Info.plist; 518 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 519 | LIBRARY_SEARCH_PATHS = ( 520 | "$(inherited)", 521 | "$(PROJECT_DIR)/Flutter", 522 | ); 523 | PRODUCT_BUNDLE_IDENTIFIER = com.rdygo.flutterTtsImprovedExample; 524 | PRODUCT_NAME = "$(TARGET_NAME)"; 525 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 526 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 527 | SWIFT_VERSION = 5.0; 528 | VERSIONING_SYSTEM = "apple-generic"; 529 | }; 530 | name = Debug; 531 | }; 532 | 97C147071CF9000F007C117D /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 535 | buildSettings = { 536 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 537 | CLANG_ENABLE_MODULES = YES; 538 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 539 | DEVELOPMENT_TEAM = 49427B483J; 540 | ENABLE_BITCODE = NO; 541 | FRAMEWORK_SEARCH_PATHS = ( 542 | "$(inherited)", 543 | "$(PROJECT_DIR)/Flutter", 544 | ); 545 | INFOPLIST_FILE = Runner/Info.plist; 546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 547 | LIBRARY_SEARCH_PATHS = ( 548 | "$(inherited)", 549 | "$(PROJECT_DIR)/Flutter", 550 | ); 551 | PRODUCT_BUNDLE_IDENTIFIER = com.rdygo.flutterTtsImprovedExample; 552 | PRODUCT_NAME = "$(TARGET_NAME)"; 553 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 554 | SWIFT_VERSION = 5.0; 555 | VERSIONING_SYSTEM = "apple-generic"; 556 | }; 557 | name = Release; 558 | }; 559 | /* End XCBuildConfiguration section */ 560 | 561 | /* Begin XCConfigurationList section */ 562 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 563 | isa = XCConfigurationList; 564 | buildConfigurations = ( 565 | 97C147031CF9000F007C117D /* Debug */, 566 | 97C147041CF9000F007C117D /* Release */, 567 | 249021D3217E4FDB00AE95B9 /* Profile */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 573 | isa = XCConfigurationList; 574 | buildConfigurations = ( 575 | 97C147061CF9000F007C117D /* Debug */, 576 | 97C147071CF9000F007C117D /* Release */, 577 | 249021D4217E4FDB00AE95B9 /* Profile */, 578 | ); 579 | defaultConfigurationIsVisible = 0; 580 | defaultConfigurationName = Release; 581 | }; 582 | /* End XCConfigurationList section */ 583 | }; 584 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 585 | } 586 | --------------------------------------------------------------------------------