提交 cd580b3e 作者: 王苏进

feat: 初始化

上级
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
build/
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
channel: "stable"
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: android
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: ios
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
## 0.0.1
* TODO: Describe initial release.
TODO: Add your license here.
# aivoice_plugin
A new Flutter plugin project.
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter development, view the
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx
group 'com.example.aivoice_plugin'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
if (project.android.hasProperty("namespace")) {
namespace 'com.example.aivoice_plugin'
}
compileSdk 34
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
test.java.srcDirs += 'src/test/kotlin'
}
defaultConfig {
minSdkVersion 19
}
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.mockito:mockito-core:5.0.0'
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}
rootProject.name = 'aivoice_plugin'
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aivoice_plugin">
</manifest>
package com.yourcompany.aivoiceplugin;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class AivoicePlugin implements FlutterPlugin, MethodCallHandler {
private MethodChannel channel;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "aivoice_plugin");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else if (call.method.equals("initEngine")) {
// 空实现
result.success(null);
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
}
\ No newline at end of file
package com.example.aivoice_plugin
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** AivoicePlugin */
class AivoicePlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "aivoice_plugin")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
package com.example.aivoice_plugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlin.test.Test
import org.mockito.Mockito
/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
internal class AivoicePluginTest {
@Test
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
val plugin = AivoicePlugin()
val call = MethodCall("getPlatformVersion", null)
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
plugin.onMethodCall(call, mockResult)
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
}
}
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
- platform: ios
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
# aivoice_plugin_example
Demonstrates how to use the aivoice_plugin plugin.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
android {
namespace "com.example.aivoice_plugin_example"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.aivoice_plugin_example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {}
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="aivoice_plugin_example"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
package com.example.aivoice_plugin_example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"
// This is a basic Flutter integration test.
//
// Since integration tests run in a full Flutter application, they can interact
// with the host side of a plugin implementation, unlike Dart unit tests.
//
// For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:aivoice_plugin/aivoice_plugin.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
final AivoicePlugin plugin = AivoicePlugin();
final String? version = await plugin.getPlatformVersion();
// The version string depends on the host platform running the test, so
// just assert that some non-empty string is returned.
expect(version?.isNotEmpty, true);
});
}
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/volcengine/volcengine-specs.git'
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks! :linkage => :static
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
PODS:
- aivoice_plugin (0.0.1):
- Flutter
- SpeechEngineToB
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- SpeechEngineToB (0.0.4):
- TTNetworkManager (= 5.0.29.22)
- TTNetworkManager (5.0.29.22)
DEPENDENCIES:
- aivoice_plugin (from `.symlinks/plugins/aivoice_plugin/ios`)
- Flutter (from `Flutter`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
SPEC REPOS:
https://github.com/volcengine/volcengine-specs.git:
- SpeechEngineToB
- TTNetworkManager
EXTERNAL SOURCES:
aivoice_plugin:
:path: ".symlinks/plugins/aivoice_plugin/ios"
Flutter:
:path: Flutter
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
SPEC CHECKSUMS:
aivoice_plugin: 994d33c97542be282047ff9ecc4766641f802c4a
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
integration_test: 13825b8a9334a850581300559b8839134b124670
SpeechEngineToB: a49185c07a099cdc052de97218bc10dc4ff60152
TTNetworkManager: 47d93100d944e2ae807e035d8636df92fd5cc390
PODFILE CHECKSUM: bde3e45995fad5550475b342803cb71575488751
COCOAPODS: 1.14.3
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
255B9587178BA958AF8D5D36 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AEFE7BC525A0C91FFF8ADFA /* Pods_RunnerTests.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
99E887E226617EE1B69F43EB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1744791E545D5488AF73C57D /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0FA079E8943B0079DEF13568 /* 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 = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
16344794BF31AD2B95D0D2E6 /* 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 = "<group>"; };
1744791E545D5488AF73C57D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2AEFE7BC525A0C91FFF8ADFA /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4918F19E97D37C43D2D522A8 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8BDA28280F6BDBDBFE64ACEF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9F23D453959CC1C9BA2A1931 /* 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 = "<group>"; };
E774E85DB7E797F8A4A2605C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
99E887E226617EE1B69F43EB /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BEBD13163208492A420413E8 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
255B9587178BA958AF8D5D36 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08DB6F7B3D829258581747F4 /* Pods */ = {
isa = PBXGroup;
children = (
9F23D453959CC1C9BA2A1931 /* Pods-Runner.debug.xcconfig */,
0FA079E8943B0079DEF13568 /* Pods-Runner.release.xcconfig */,
16344794BF31AD2B95D0D2E6 /* Pods-Runner.profile.xcconfig */,
4918F19E97D37C43D2D522A8 /* Pods-RunnerTests.debug.xcconfig */,
E774E85DB7E797F8A4A2605C /* Pods-RunnerTests.release.xcconfig */,
8BDA28280F6BDBDBFE64ACEF /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
08DB6F7B3D829258581747F4 /* Pods */,
9EA04C6F298AA8CD5686B1F6 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
9EA04C6F298AA8CD5686B1F6 /* Frameworks */ = {
isa = PBXGroup;
children = (
1744791E545D5488AF73C57D /* Pods_Runner.framework */,
2AEFE7BC525A0C91FFF8ADFA /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
AF5927625FFC899C49CB49B4 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
BEBD13163208492A420413E8 /* Frameworks */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
CB223D02D0AAE4C1C02D4887 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
85B4D4D8544FEB70E34F075F /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
85B4D4D8544FEB70E34F075F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AF5927625FFC899C49CB49B4 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
CB223D02D0AAE4C1C02D4887 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 4918F19E97D37C43D2D522A8 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E774E85DB7E797F8A4A2605C /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8BDA28280F6BDBDBFE64ACEF /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = ZTL5A6WMHV;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
#import "GeneratedPluginRegistrant.h"
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:aivoice_plugin/aivoice_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _aivoicePlugin = AivoicePlugin();
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion =
await _aivoicePlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
),
);
}
}
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
aivoice_plugin:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "0.0.1"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
version: "1.0.8"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_driver:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
integration_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
url: "https://pub.dev"
source: hosted
version: "2.0.1"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
url: "https://pub.dev"
source: hosted
version: "2.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "3.0.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
version: "1.11.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
platform:
dependency: transitive
description:
name: platform
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
process:
dependency: transitive
description:
name: process
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
sync_http:
dependency: transitive
description:
name: sync_http
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
url: "https://pub.dev"
source: hosted
version: "13.0.0"
webdriver:
dependency: transitive
description:
name: webdriver
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
sdks:
dart: ">=3.3.4 <4.0.0"
flutter: ">=3.3.0"
name: aivoice_plugin_example
description: "Demonstrates how to use the aivoice_plugin plugin."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment:
sdk: '>=3.3.4 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
aivoice_plugin:
# When depending on this package from a real application you should use:
# aivoice_plugin: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
dev_dependencies:
integration_test:
sdk: flutter
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:aivoice_plugin_example/main.dart';
void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that platform version is retrieved.
expect(
find.byWidgetPredicate(
(Widget widget) => widget is Text &&
widget.data!.startsWith('Running on:'),
),
findsOneWidget,
);
});
}
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/ephemeral/
/Flutter/flutter_export_environment.sh
\ No newline at end of file
#import <Flutter/Flutter.h>
@interface AivoicePlugin : NSObject<FlutterPlugin>
@end
#import "AivoicePlugin.h"
@interface AivoicePlugin ()
@end
@implementation AivoicePlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"aivoice_plugin"
binaryMessenger:[registrar messenger]];
AivoicePlugin* instance = [[AivoicePlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else if ([@"initEngine" isEqualToString:call.method]) {
// 空实现
result(nil);
} else {
result(FlutterMethodNotImplemented);
}
}
@end
//
// FileRecorder.h
// SpeechDemo
//
// Created by fangweiwei on 2021/8/31.
// Copyright © 2021 fangweiwei. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <SpeechEngineToB/SpeechEngine.h>
NS_ASSUME_NONNULL_BEGIN
@interface FileRecorder : NSObject
- (void)setSpeechEngine:(SpeechEngine *)engine;
- (BOOL)startWithPath:(NSString *)path filename:(NSString *)filename;
- (void)stop;
@end
NS_ASSUME_NONNULL_END
//
// FileRecorder.m
// SpeechDemo
//
// Created by fangweiwei on 2021/8/31.
// Copyright © 2021 fangweiwei. All rights reserved.
//
#import "FileRecorder.h"
#import "FileUtils.h"
@interface FileRecorder ()
@property (nonatomic, weak) SpeechEngine *curEngine;
@property (nonatomic, strong) NSThread *worker;
@property (nonatomic, copy) NSString *path;
@property (nonatomic, copy) NSString *filename;
@end
@implementation FileRecorder
- (instancetype)init
{
self = [super init];
if (self) {
_worker = nil;
}
return self;
}
- (void)setSpeechEngine:(SpeechEngine *)engine {
self.curEngine = engine;
}
- (BOOL)startWithPath:(NSString *)path filename:(NSString *)filename {
if (self.worker) {
if (self.worker.executing) {
NSLog(@"Already start!");
return TRUE;
}
[self.worker cancel];
self.worker = nil;
}
self.path = path;
self.filename = filename;
self.worker = [[NSThread alloc] initWithTarget:self selector:@selector(runner) object:nil];
[self.worker start];
return TRUE;
}
- (void)stop {
if (!self.worker) {
NSLog(@"Not start yet!");
return;
}
[self.worker cancel];
self.worker = nil;
}
- (void)runner {
NSUInteger dataLength = 8000 * 2 * 0.1;
NSFileHandle *file = [FileUtils openFileForReading:self.filename inPath:self.path];
NSUInteger total = 0;
while (!self.worker.cancelled) {
NSData *data;
if (![FileUtils readData:&data length:dataLength fromFileHandel:file]) {
break;
}
total += data.length;
if (data.length > 0) {
SEErrorCode ret = [self.curEngine feedAudio:(int16_t *)data.bytes length:(int32_t)(data.length / 2)];
if (ret) {
NSLog(@"Feed audio data failed: %d, lenght: %lu.", ret, (unsigned long)(data.length / 2));
break;
}
} else {
NSLog(@"Finished reading");
break;
}
}
NSLog(@"Read tatal: %lu", (unsigned long)total);
[FileUtils closeFile:file];
}
@end
//
// FileUtils.h
// SpeechDemo
//
// Created by fangweiwei on 2020/6/16.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface FileUtils : NSObject
+ (NSFileHandle *)openFileForReading:(NSString *)filename inPath:(NSString *)path;
+ (NSFileHandle *)openFileForWriting:(NSString *)filename inPath:(NSString *)path;
+ (BOOL)writeData:(NSData *)data toFileHandel:(NSFileHandle *)fileHandle;
+ (BOOL)readData:(NSData *_Nullable*_Nullable)data length:(NSUInteger)length fromFileHandel:(NSFileHandle *)fileHandle;
+ (void)closeFile:(NSFileHandle *)filehandle;
@end
NS_ASSUME_NONNULL_END
//
// FileUtils.m
// SpeechDemo
//
// Created by fangweiwei on 2020/6/16.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#import "FileUtils.h"
@implementation FileUtils
+ (NSFileHandle *)openFileForReading:(NSString *)filename inPath:(NSString *)path {
NSString *filePath = [path stringByAppendingPathComponent:filename];
return [NSFileHandle fileHandleForReadingAtPath:filePath];
}
+ (NSFileHandle *)openFileForWriting:(NSString *)filename inPath:(NSString *)path {
NSString *filePath = [path stringByAppendingPathComponent:filename];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
return [NSFileHandle fileHandleForUpdatingAtPath:filePath];
}
+ (BOOL)writeData:(NSData *)data toFileHandel:(NSFileHandle *)fileHandle {
if (fileHandle && data) {
@try {
[fileHandle writeData:data];
} @catch (NSException *exception) {
NSLog(@"FileUtils, write data failed: %@", exception.description);
return FALSE;
}
return TRUE;
}
return FALSE;
}
+ (BOOL)readData:(NSData **)data length:(NSUInteger)length fromFileHandel:(NSFileHandle *)fileHandle {
if (fileHandle && data) {
NSError *err;
if (@available(iOS 13.0, *)) {
*data = [fileHandle readDataUpToLength:length error:&err];
if (err) {
NSLog(@"FileUtils read data failed: %@.", err);
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
+ (void)closeFile:(NSFileHandle *)filehandle {
if (filehandle) {
[filehandle closeFile];
}
}
@end
//
// SensitiveDefines.h
// SpeechDemo
//
// Created by bytedance on 2022/12/9.
// Copyright © 2022 tianlei.richard. All rights reserved.
//
#define SensitiveDefines_h
/**
* SensitiveDefines
* Defines in this class should be different for different business,
* please contact with @Bytedance AILab about what value should be set before use it.
*/
// User Info
extern NSString* SDEF_UID;
// Online & Resource Authentication
extern NSString* SDEF_APPID;
extern NSString* SDEF_TOKEN;
extern NSString* SDEF_APP_VERSION;
// Offline Authentication
extern NSString* SDEF_AUTHENTICATE_ADDRESS;
extern NSString* SDEF_AUTHENTICATE_URI;
extern NSString* SDEF_SECRET;
extern NSString* SDEF_BUSINESS_KEY;
extern NSString* SDEF_LICENSE_NAME;
extern NSString* SDEF_LICENSE_BUSI_ID;
// Address
extern NSString* SDEF_DEFAULT_ADDRESS;
extern NSString* SDEF_DEFAULT_HTTP_ADDRESS;
// ASR
extern NSString* SDEF_ASR_DEFAULT_CLUSTER;
extern NSString* SDEF_ASR_DEFAULT_URI;
// AU
extern NSString* SDEF_AU_DEFAULT_CLUSTER;
extern NSString* SDEF_AU_DEFAULT_URI;
// TTS
extern NSString* SDEF_TTS_DEFAULT_URI;
extern NSString* SDEF_TTS_DEFAULT_CLUSTER;
extern NSString* SDEF_TTS_DEFAULT_BACKEND_CLUSTER;
extern NSString* SDEF_TTS_DEFAULT_ONLINE_VOICE;
extern NSString* SDEF_TTS_DEFAULT_ONLINE_VOICE_TYPE;
extern NSString* SDEF_TTS_DEFAULT_OFFLINE_VOICE;
extern NSString* SDEF_TTS_DEFAULT_OFFLINE_VOICE_TYPE;
extern NSString* SDEF_TTS_DEFAULT_ONLINE_LANGUAGE;
extern NSString* SDEF_TTS_DEFAULT_OFFLINE_LANGUAGE;
const NSArray* SDEF_TTS_DEFAULT_DOWNLOAD_OFFLINE_VOICES();
// VoiceClone
extern NSString* SDEF_VOICECLONE_DEFAULT_UIDS;
extern int SDEF_VOICECLONE_DEFAULT_TASK_ID;
// VoiceConv
extern NSString* SDEF_VOICECONV_DEFAULT_URI;
extern NSString* SDEF_VOICECONV_DEFAULT_CLUSTER;
extern NSString* SDEF_VOICECONV_DEFAULT_VOICE;
extern NSString* SDEF_VOICECONV_DEFAULT_VOICE_TYPE;
// Fulllink
extern NSString* SDEF_FULLLINK_DEFAULT_URI;
// Dialog
extern NSString* SDEF_DIALOG_DEFAULT_URI;
extern NSString* SDEF_DIALOG_DEFAULT_APP_ID;
extern NSString* SDEF_DIALOG_DEFAULT_ID;
extern NSString* SDEF_DIALOG_DEFAULT_ROLE;
extern NSString* SDEF_DIALOG_DEFAULT_CLOTHES_TYPE;
extern NSString* SDEF_DIALOG_DEFAULT_TTA_VOICE_TYPE;
// CAPT
extern NSString* SDEF_CAPT_DEFAULT_MDD_URI;
extern NSString* SDEF_CAPT_DEFAULT_CLUSTER;
//
// SensitiveDefines.m
// SpeechDemo
//
// Created by bytedance on 2022/12/9.
// Copyright © 2022 tianlei.richard. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SensitiveDefines.h"
// User Info
const NSString* SDEF_UID = @"YOUR UID";
// Online & Resource Authentication
const NSString* SDEF_APPID = @"2301072440";
const NSString* SDEF_TOKEN = @"Bearer;75UvJCpxRjTCppqQUkQ-o-4UfjnCgVmp";//;
const NSString* SDEF_APP_VERSION = @"1.0.0";
// Offline Authentication
const NSString* SDEF_AUTHENTICATE_ADDRESS = @"AUTHENTICAT ADDRESS";
const NSString* SDEF_AUTHENTICATE_URI = @"AUTHENTICATE URI";
const NSString* SDEF_SECRET = @"YOUR SECRET";
const NSString* SDEF_BUSINESS_KEY = @"YOUR BUSINESS KEY";
const NSString* SDEF_LICENSE_NAME = @"YOUR LICENSE NAME";
const NSString* SDEF_LICENSE_BUSI_ID = @"YOUR LICENSE BUSI_ID";
// Address
const NSString* SDEF_DEFAULT_ADDRESS = @"wss://openspeech.bytedance.com";
const NSString* SDEF_DEFAULT_HTTP_ADDRESS = @"https://openspeech.bytedance.com";
// ASR
const NSString* SDEF_ASR_DEFAULT_CLUSTER = @"volcengine_streaming_common";
const NSString* SDEF_ASR_DEFAULT_URI = @"/api/v2/asr";
// AU
const NSString* SDEF_AU_DEFAULT_CLUSTER = @"YOUR AU CLUSTER";
const NSString* SDEF_AU_DEFAULT_URI = @"/api/v1/sauc";
// TTS
const NSString* SDEF_TTS_DEFAULT_URI = @"/api/v1/tts/ws_binary";
const NSString* SDEF_TTS_DEFAULT_CLUSTER = @"volcano_tts";
const NSString* SDEF_TTS_DEFAULT_BACKEND_CLUSTER = @"YOUR TTS BACKEND CLUSTER";
const NSString* SDEF_TTS_DEFAULT_ONLINE_VOICE = @"灿灿";
const NSString* SDEF_TTS_DEFAULT_ONLINE_VOICE_TYPE = @"BV213_w5H18f6VbKnhg3Ph";
//BV002_streaming BV021_PSj8BvWAZyepfUPB BV705_streaming BV115_H74MBi790rUFu993 BV213_w5H18f6VbKnhg3Ph
const NSString* SDEF_TTS_DEFAULT_OFFLINE_VOICE = @"YOUR TTS OFFLINE VOICE";
const NSString* SDEF_TTS_DEFAULT_OFFLINE_VOICE_TYPE = @"YOUR TTS OFFLINE VOICE TYPE";
const NSString* SDEF_TTS_DEFAULT_ONLINE_LANGUAGE = @"YOUT TTS ONLINE LANGUAGE";
const NSString* SDEF_TTS_DEFAULT_OFFLINE_LANGUAGE = @"YOUT TTS OFFLINE LANGUAGE";
const NSArray* SDEF_TTS_DEFAULT_DOWNLOAD_OFFLINE_VOICES() { return @[]; }
// VoiceClone
const NSString* SDEF_VOICECLONE_DEFAULT_UIDS = @"uid_1;uid_2";
int SDEF_VOICECLONE_DEFAULT_TASK_ID = -1;
// VoiceConv
const NSString* SDEF_VOICECONV_DEFAULT_URI = @"/api/v1/voice_conv/ws";
const NSString* SDEF_VOICECONV_DEFAULT_CLUSTER = @"YOUR VOICECONV CLUSTER";
const NSString* SDEF_VOICECONV_DEFAULT_VOICE = @"VOICECONV VOICE";
const NSString* SDEF_VOICECONV_DEFAULT_VOICE_TYPE = @"VOICECONV VOICE TYPE";
// Fulllink
const NSString* SDEF_FULLLINK_DEFAULT_URI = @"FULLLINK URI";
// Dialog
const NSString* SDEF_DIALOG_DEFAULT_URI = @"DIALOG URI";
const NSString* SDEF_DIALOG_DEFAULT_APP_ID = @"DIALOG APP ID";
const NSString* SDEF_DIALOG_DEFAULT_ID = @"DIALOG ID";
const NSString* SDEF_DIALOG_DEFAULT_ROLE = @"DIALOG ROLE";
const NSString* SDEF_DIALOG_DEFAULT_CLOTHES_TYPE = @"DIALOG CLOTHES TYPE";
const NSString* SDEF_DIALOG_DEFAULT_TTA_VOICE_TYPE = @"DIALOG TTA_VOICE_TYPE";
// CAPT
const NSString* SDEF_CAPT_DEFAULT_MDD_URI = @"CAPT MDD URI";
const NSString* SDEF_CAPT_DEFAULT_CLUSTER = @"YOUR CAPT CLUSTER";
//
// SettingViewDelegate.h
// SpeechDemo
//
// Created by bytedance on 2021/3/26.
// Copyright © 2021 chengzihao.ds. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Settings.h"
#pragma mark - SettingItemCell
@interface SettingItemCell : UITableViewCell<UITextFieldDelegate>
@property (weak, nonatomic) Settings *settings;
@property (weak, nonatomic) UITableView* parent;
-(void)init:(Settings*)settings parent:(UITableView*)parent;
-(SettingItem*)getCorrespondItem;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
@end
#pragma mark - SettingBoolCell
@interface SettingBoolCell : SettingItemCell
@property (weak, nonatomic) IBOutlet UILabel *keyLabel;
@property (weak, nonatomic) IBOutlet UISwitch *valSwitch;
-(void)switchAction:(UISwitch*)sender;
@end
#pragma mark - SettingIntCell
@interface SettingIntCell : SettingItemCell
@property (weak, nonatomic) IBOutlet UILabel *keyLabel;
@property (weak, nonatomic) IBOutlet UITextField *valTextField;
-(void)textFieldDidChange :(UITextField *)textField;
@end
#pragma mark - SettingStringCell
@interface SettingStringCell : SettingItemCell
@property (weak, nonatomic) IBOutlet UILabel *keyLabel;
@property (weak, nonatomic) IBOutlet UITextField *valTextField;
-(void)textFieldDidChange :(UITextField *)textField;
@end
#pragma mark - SettingOptionsCell
@interface SettingOptionsCell : SettingItemCell<UIPickerViewDelegate, UIPickerViewDataSource>
@property (weak, nonatomic) IBOutlet UILabel *keyLabel;
@property (weak, nonatomic) IBOutlet UITextField *valTextField;
@property (strong, nonatomic) UIPickerView *pickerView;
@property (strong, nonatomic) UIToolbar *pickerToolbar;
-(void)pickerConfirm;
-(void)pickerCancel;
@end
#pragma mark - SettingViewDelegate
@interface SettingViewDelegate : NSObject<UITableViewDelegate, UITableViewDataSource>
@property (strong, nonatomic) Settings* settings;
+ (instancetype)build:(Settings*)settings;
@end
//
// SettingViewDelegate.m
// SpeechDemo
//
// Created by bytedance on 2021/3/26.
// Copyright © 2021 chengzihao.ds. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SettingViewDelegate.h"
#pragma mark - SettingItemCell
@implementation SettingItemCell
-(void)init:(Settings*)settings parent:(UITableView*)parent {
self.settings = settings;
self.parent = parent;
}
-(SettingItem*)getCorrespondItem {
NSIndexPath* path = [self.parent indexPathForCell:self];
NSMutableArray* group = self.settings.configs[path.section];
return group[path.row];
}
// auto close keyboard when click return
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
@end
#pragma mark - SettingBoolCell
@implementation SettingBoolCell
-(void)init:(Settings*)settings parent:(UITableView*)parent {
[super init:settings parent:parent];
[self.valSwitch addTarget:self action:@selector(switchAction:) forControlEvents:UIControlEventValueChanged];
}
-(void)switchAction:(UISwitch*)sender {
SettingItem* item = [self getCorrespondItem];
[self.settings setBool:item.key val:sender.isOn];
}
@end
#pragma mark - SettingIntCell
@implementation SettingIntCell
-(void)init:(Settings*)settings parent:(UITableView*)parent {
[super init:settings parent:parent];
self.valTextField.delegate = self;
[self.valTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
-(void)textFieldDidChange :(UITextField *)textField {
SettingItem* item = [self getCorrespondItem];
// if input empty, do nothing
if ([textField.text length] > 0) {
[self.settings setInt:item.key val:[textField.text intValue]];
}
}
@end
#pragma mark - SettingStringCell
@implementation SettingStringCell
-(void)init:(Settings*)settings parent:(UITableView*)parent {
[super init:settings parent:parent];
self.valTextField.delegate = self;
[self.valTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
-(void)textFieldDidChange :(UITextField *)textField {
SettingItem* item = [self getCorrespondItem];
[self.settings setString:item.key val:textField.text];
}
@end
#pragma mark - SettingOptionsCell
@implementation SettingOptionsCell
-(void)init:(Settings*)settings parent:(UITableView*)parent {
[super init:settings parent:parent];
// init picker view
self.pickerView = [[UIPickerView alloc] init];
self.pickerView.dataSource = self;
self.pickerView.delegate = self;
// init picker toolbar
self.pickerToolbar = [[UIToolbar alloc]initWithFrame:
CGRectMake(0, self.frame.size.height-
self.pickerView.frame.size.height-20, self.bounds.size.width, 40)];
UIBarButtonItem *confirmBtn = [[UIBarButtonItem alloc] initWithTitle:@"Confirm" style:UIBarButtonItemStyleDone target:self action:@selector(pickerConfirm)];
UIBarButtonItem *flexibleBBI = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[self.pickerToolbar setBarStyle:UIBarStyleDefault];
NSArray *toolbarItems = [NSArray arrayWithObjects:flexibleBBI, confirmBtn, nil];
[self.pickerToolbar setItems:toolbarItems];
// show pickerView
self.valTextField.delegate = self;
self.valTextField.inputView = self.pickerView;
self.valTextField.inputAccessoryView = self.pickerToolbar;
}
// PickerView width
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
return self.bounds.size.width;
}
// PickerView select event
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
SettingItem* item = [self getCorrespondItem];
SettingOptions* options = (SettingOptions*)item.value;
options.chooseIdx = (int)row;
[self.settings setOptions:item.key val:options];
[self.valTextField setText:options.optionsArray[row]];
}
// PickerView show options
-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
SettingItem* item = [self getCorrespondItem];
SettingOptions* options = (SettingOptions*)item.value;
return options.optionsArray[row];
}
// PickerView column number
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
// PickerView row number for each column
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
SettingItem* item = [self getCorrespondItem];
return ((SettingOptions*)item.value).optionsArray.count;
}
// PickerToolbar confirm button click event
-(void)pickerConfirm {
if ([self.valTextField isFirstResponder]) {
[self.valTextField resignFirstResponder];
}
}
@end
#pragma mark - SettingViewDelegate
@implementation SettingViewDelegate
static NSString* nibName = @"SpeechSettingItem";
static CGFloat sectionHeaderHeight = 30;
static CGFloat sectionFooterHeight = 30;
+ (instancetype)build:(Settings*)settings {
SettingViewDelegate* instance = [[self alloc] init];
instance.settings = settings;
return instance;
}
// row number for each section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSMutableArray *curGroup = _settings.configs[section];
NSLog(@"numberOfRowsInSection %ld", curGroup.count);
return curGroup.count;
}
// section number
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(@"numberOfSectionsInTableView %ld", _settings.groups.count);
return _settings.groups.count;
}
// section title
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
SettingItem *groupItem = _settings.groups[section];
return groupItem.key;
}
// section header height
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return sectionHeaderHeight;
}
// section footer height
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return sectionFooterHeight;
}
// generate TableViewCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell;
NSMutableArray* group = _settings.configs[indexPath.section];
SettingItem* item = group[indexPath.row];
NSString *CellTableIndentifier = NULL;
switch (item.type) {
case kSettingBool:
{
CellTableIndentifier = @"SettingBool";
SettingBoolCell* bCell = [tableView dequeueReusableCellWithIdentifier:CellTableIndentifier];
if(bCell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
bCell = [nib objectAtIndex:item.type];
[bCell init:_settings parent:tableView];
}
[bCell.keyLabel setText:item.key];
[bCell.valSwitch setOn:[(NSNumber*)item.value intValue] == 1];
cell = bCell;
}
break;
case kSettingInt:
{
CellTableIndentifier = @"SettingInt";
SettingIntCell *iCell = [tableView dequeueReusableCellWithIdentifier:CellTableIndentifier];
if(iCell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
iCell = [nib objectAtIndex:item.type];
[iCell init:_settings parent:tableView];
}
[iCell.keyLabel setText:item.key];
[iCell.valTextField setText:[(NSNumber*)item.value stringValue]];
[iCell.valTextField setPlaceholder:(NSString*)item.hint];
cell = iCell;
}
break;
case kSettingString:
{
CellTableIndentifier = @"SettingString";
SettingStringCell *sCell = [tableView dequeueReusableCellWithIdentifier:CellTableIndentifier];
if(sCell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
sCell = [nib objectAtIndex:item.type];
[sCell init:_settings parent:tableView];
}
[sCell.keyLabel setText:item.key];
[sCell.valTextField setText:(NSString*)item.value];
[sCell.valTextField setPlaceholder:(NSString*)item.hint];
cell = sCell;
}
break;
case kSettingOptions:
{
CellTableIndentifier = @"SettingOptions";
SettingOptionsCell *oCell = [tableView dequeueReusableCellWithIdentifier:CellTableIndentifier];
if(oCell == nil) {
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
oCell = [nib objectAtIndex:item.type];
[oCell init:_settings parent:tableView];
}
SettingOptions *options = (SettingOptions*)item.value;
[oCell.keyLabel setText:item.key];
[oCell.valTextField setText:options.optionsArray[options.chooseIdx]];
[oCell.valTextField setPlaceholder:item.hint];
cell = oCell;
}
break;
default:
NSLog(@"Unsupported SettingType: %ld", item.type);
break;
}
cell.accessibilityIdentifier = item.key;
return cell;
}
@synthesize description;
@synthesize hash;
@synthesize superclass;
@end
//
// Settings.h
// SpeechDemo
//
// Created by bytedance on 2021/3/26.
// Copyright © 2021 chengzihao.ds. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#pragma mark - SettingType
typedef NS_ENUM(NSInteger, SettingType) {
kSettingGroup = 0,
kSettingBool = 1,
kSettingInt = 2,
kSettingString = 3,
kSettingOptions = 4,
};
#pragma mark - SettingOptions
@interface SettingOptions : NSObject
@property (strong, nonatomic) NSArray* optionsArray;
@property (assign, nonatomic) int chooseIdx;
+ (instancetype)build:(NSArray*)ops choose:(int)idx;
@end
#pragma mark - SettingItem
@interface SettingItem : NSObject
@property (assign, nonatomic) SettingType type;
@property (strong, nonatomic) NSString* key;
@property (strong, nonatomic) NSObject* value;
@property (strong, nonatomic) NSString* hint;
+ (instancetype)build:(SettingType)type key:(NSString*)key val:(NSObject*)val hint:(NSString*)hint;
+ (instancetype)buildGroup:(NSString*)key val:(NSString*)val hint:(NSString*)hint;
+ (instancetype)buildBool:(NSString*)key val:(BOOL)val hint:(NSString*)hint;
+ (instancetype)buildInt:(NSString*)key val:(int)val hint:(NSString*)hint;
+ (instancetype)buildString:(NSString*)key val:(NSString*)val hint:(NSString*)hint;
+ (instancetype)buildOptions:(NSString*)key val:(SettingOptions*)val hint:(NSString*)hint;
@end
#pragma mark - Settings
@interface Settings : NSObject
// kSettingGroup type, use SettingItem 1 dimension array.
@property (strong, nonatomic) NSMutableArray* groups;
// other type, use SettingItem 2 dimension array. 1st dimension for each group, 2nd dimension for detail SettingItem in group.
@property (strong, nonatomic) NSMutableArray* configs;
+ (instancetype)build;
- (void)registerItems:(NSArray*)cfgs;
- (void)setBool:(NSString*)key;
- (void)setBool:(NSString*)key val:(BOOL)val;
- (void)setInt:(NSString*)key;
- (void)setInt:(NSString*)key val:(int)val;
- (void)setString:(NSString*)key;
- (void)setString:(NSString*)key val:(NSString*)val;
- (void)setOptions:(NSString*)key;
- (void)setOptions:(NSString*)key val:(SettingOptions*)val;
- (BOOL)getBool:(NSString*)key;
- (BOOL)getBool:(NSString*)key def:(BOOL)def;
- (int)getInt:(NSString*)key;
- (int)getInt:(NSString*)key def:(int)def;
- (NSString*)getString:(NSString*)key;
- (NSString*)getString:(NSString*)key def:(NSString*)def;
- (SettingOptions*)getOptions:(NSString*)key;
- (SettingOptions*)getOptions:(NSString*)key def:(SettingOptions*)def;
- (NSString*)getOptionsValue:(NSString*)key;
@end
NS_ASSUME_NONNULL_END
//
// Settings.m
// SpeechDemo
//
// Created by bytedance on 2021/3/26.
// Copyright © 2021 chengzihao.ds. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Settings.h"
#pragma mark - SettingOptions
@implementation SettingOptions
+ (instancetype)build:(NSArray*)ops choose:(int)idx {
SettingOptions* instance = [[self alloc] init];
instance.optionsArray = ops;
instance.chooseIdx = idx;
return instance;
}
@end
#pragma mark - SettingItem
@implementation SettingItem
+ (instancetype)build:(SettingType)type key:(NSString*)key val:(NSObject*)val hint:(NSString*)hint {
SettingItem* instance = [[self alloc] init];
instance.key = key;
instance.type = type;
instance.value = val;
instance.hint = hint;
return instance;
}
+ (instancetype)buildGroup:(NSString*)key val:(NSString*)val hint:(NSString*)hint {
return [SettingItem build:kSettingGroup key:key val:val hint:hint];
}
+ (instancetype)buildBool:(NSString*)key val:(BOOL)val hint:(NSString*)hint {
return [SettingItem build:kSettingBool key:key val:val ? @1 : @0 hint:hint];
}
+ (instancetype)buildInt:(NSString*)key val:(int)val hint:(NSString*)hint {
return [SettingItem build:kSettingInt key:key val:@(val) hint:hint];
}
+ (instancetype)buildString:(NSString*)key val:(NSString*)val hint:(NSString*)hint {
return [SettingItem build:kSettingString key:key val:val hint:hint];
}
+ (instancetype)buildOptions:(NSString*)key val:(SettingOptions*)val hint:(NSString*)hint {
return [SettingItem build:kSettingOptions key:key val:val hint:hint];
}
@end
#pragma mark - Settings
@implementation Settings
+ (instancetype)build {
Settings* instance = [[self alloc] init];
instance.groups = [[NSMutableArray alloc]init];
instance.configs = [[NSMutableArray alloc]init];
// configs has at least one group
[instance.configs addObject:[[NSMutableArray alloc] init]];
return instance;
}
- (void)setItem:(SettingItem*)item {
if (item.type == kSettingGroup) {
// group type
for (int i = 0; i < _groups.count; ++i) {
SettingItem* groupItem = _groups[i];
if ([groupItem.key isEqualToString:item.key]) {
// same group exist, do nothing
return;
}
}
[_groups addObject:item];
NSMutableArray* group = _configs[0];
if (_configs.count == 1 && group.count == 0) {
// first group has no items yet, means this is first group
return;
}
// append new group
[_configs addObject:[[NSMutableArray alloc] init]];
return;
} else {
// other type
NSMutableArray* group = NULL;
for (int i = 0; i < _configs.count; ++i) {
group = _configs[i];
for (int j = 0; j < group.count; ++j) {
SettingItem* cur = group[j];
if ([cur.key isEqualToString:item.key]) {
_configs[i][j] = item;
return;
}
}
}
// default add to last group
[group addObject:item];
}
}
- (SettingItem*)getItem:(NSString*)key type:(SettingType)type {
if (type == kSettingGroup) {
// group type
for (int i = 0; i < _groups.count; ++i) {
SettingItem* cur = _groups[i];
if ([cur.key isEqualToString:key]) {
return cur;
}
}
return NULL;
} else {
// other type
for (int i = 0; i < _configs.count; ++i) {
NSMutableArray* group = _configs[i];
for (int j = 0; j < group.count; ++j) {
SettingItem* cur = group[j];
if ([cur.key isEqualToString:key]) {
if (cur.type == type) {
return cur;
}
return NULL;
}
}
}
return NULL;
}
return NULL;
}
- (void)registerItems:(NSArray*)cfgs {
for (int i = 0; i < cfgs.count; ++i) {
[self setItem:cfgs[i]];
}
}
- (void)setBool:(NSString*)key {
[self setBool:key val:false];
}
- (void)setBool:(NSString*)key val:(BOOL)val {
[self setItem:[SettingItem buildBool:key val:val hint:@""]];
}
- (void)setInt:(NSString*)key {
[self setInt:key val:0];
}
- (void)setInt:(NSString*)key val:(int)val {
[self setItem:[SettingItem buildInt:key val:val hint:@""]];
}
- (void)setString:(NSString*)key {
[self setString:key val:@""];
}
- (void)setString:(NSString*)key val:(NSString*)val {
[self setItem:[SettingItem buildString:key val:val hint:@""]];
}
- (void)setOptions:(NSString*)key {
[self setOptions:key val:[SettingOptions build:@[] choose:0]];
}
- (void)setOptions:(NSString*)key val:(SettingOptions*)val {
[self setItem:[SettingItem buildOptions:key val:val hint:@""]];
}
- (BOOL)getBool:(NSString*)key {
return [self getBool:key def:false];
}
- (BOOL)getBool:(NSString*)key def:(BOOL)def {
SettingItem* item = [self getItem:key type:kSettingBool];
if (item != NULL) {
NSNumber* val = (NSNumber*)item.value;
return [val intValue] == 1;
}
return def;
}
- (int)getInt:(NSString*)key {
return [self getInt:key def:0];
}
- (int)getInt:(NSString*)key def:(int)def {
SettingItem* item = [self getItem:key type:kSettingInt];
if (item != NULL) {
NSNumber* val = (NSNumber*)item.value;
return [val intValue];
}
return def;
}
- (NSString*)getString:(NSString*)key {
return [self getString:key def:@""];
}
- (NSString*)getString:(NSString*)key def:(NSString*)def {
SettingItem* item = [self getItem:key type:kSettingString];
if (item != NULL) {
return (NSString*)item.value;
}
return def;
}
- (SettingOptions*)getOptions:(NSString*)key {
return [self getOptions:key def:[SettingOptions build:@[] choose:0]];
}
- (SettingOptions*)getOptions:(NSString*)key def:(SettingOptions*)def {
SettingItem* item = [self getItem:key type:kSettingOptions];
if (item != NULL) {
return (SettingOptions*)item.value;
}
return def;
}
- (NSString*)getOptionsValue:(NSString*)key {
SettingItem* item = [self getItem:key type:kSettingOptions];
if (item != NULL) {
SettingOptions *options = (SettingOptions*)item.value;
return options.optionsArray[options.chooseIdx];
}
return @"";
}
@end
//
// SettingsHelper.h
// SpeechDemo
//
// Created by bytedance on 2020/9/9.
// Copyright © 2020 fengkai.0518. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Settings.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark - SETTING_KEY
// common
extern NSString *const SETTING_COMMON;
extern NSString *const SETTING_APPID;
extern NSString *const SETTING_TOKEN;
extern NSString *const SETTING_CLUSTER;
extern NSString *const SETTING_ADDRESS;
extern NSString *const SETTING_URI;
extern NSString *const SETTING_VOICE;
extern NSString *const SETTING_VOICE_TYPE;
extern NSString *const SETTING_ONLINE_VOICE;
extern NSString *const SETTING_ONLINE_VOICE_TYPE;
extern NSString *const SETTING_OFFLINE_VOICE;
extern NSString *const SETTING_OFFLINE_VOICE_TYPE;
extern NSString *const SETTING_GET_VOLUME;
extern NSString *const SETTING_RECORD_TYPE;
extern NSString *const SETTING_RECORD_SAVE;
extern NSString *const SETTING_RECORD_FILE_TYPE;
extern NSString *const SETTING_SAMPLE_RATE;
extern NSString *const SETTING_CHANNEL;
extern NSString *const SETTING_ENABLE_AEC;
extern NSString *const SETTING_RESTART_AUDIO_SESSION_ENABLE;
extern NSString *const SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE;
extern NSString *const SETTING_AUTHENTICATION_TYPE;
extern NSString *const SETTING_BUSINESS_KEY;
extern NSString *const SETTING_AUTHENTICATE_SECRET;
extern NSString *const SETTING_AUDIO_FADEOUT_DURATION;
extern NSString *const SETTING_VAD_MAX_SPEECH_DURATION;
extern NSString *const SETTING_VAD_MAX_MUSIC_DURATION;
extern NSString *const SETTING_STREAM_PACKAGE_DURATION;
// asr
extern NSString *const SETTING_ASR;
extern NSString *const SETTING_ASR_WORK_MODE;
extern NSString *const SETTING_ASR_SCENARIO_TYPE;
extern NSString *const SETTING_ASR_RECORDER_SAVE;
extern NSString *const SETTING_ASR_ENABLE_DDC;
extern NSString *const SETTING_ASR_ENABLE_ITN;
extern NSString *const SETTING_ASR_ENABLE_NLU_PUNC;
extern NSString *const SETTING_ASR_DISABLE_END_PUNC;
extern NSString *const SETTING_ASR_KEEP_RECORDING;
extern NSString *const SETTING_ASR_HOTWORDS;
extern NSString *const SETTING_ASR_CORRECTWORDS;
extern NSString *const SETTING_ASR_VAD_START_SILENCE_TIME;
extern NSString *const SETTING_ASR_VAD_END_SILENCE_TIME;
extern NSString *const SETTING_ASR_VAD_MODE;
extern NSString *const SETTING_ASR_RESULT_TYPE;
extern NSString *const SETTING_ASR_MAX_RETRY_TIMES;
extern NSString *const SETTING_ASR_SHOW_LANGUAGE;
extern NSString *const SETTING_ASR_LANGUAGE;
extern NSString *const SETTING_ASR_AUTO_STOP;
// capt
extern NSString *const SETTING_CAPT;
extern NSString *const SETTING_CAPT_RECORDER_SAVE;
extern NSString *const SETTING_CAPT_STREAMING_MODE;
extern NSString *const SETTING_CAPT_CORE_TYPE;
extern NSString *const SETTING_CAPT_DIFFICULTY_LEVEL;
// fulllink
extern NSString *const SETTING_FULLLINK;
extern NSString *const SETTING_FULLLINK_ENGINE_TYPE;
extern NSString *const SETTING_FULLLINK_WAKEUP_WORDS;
extern NSString *const SETTING_FULLLINK_ENABLE_RECORDER_DUMP;
extern NSString *const SETTING_FULLLINK_ENABLE_KWS_DUMP;
extern NSString *const SETTING_FULLLINK_WAKEUP_MODE;
extern NSString *const SETTING_FULLLINK_ONLY_ASR;
extern NSString *const SETTING_FULLLINK_DISABLE_TTS;
extern NSString *const SETTING_FULLLINK_DISABLE_SIGNAL;
extern NSString *const SETTING_FULLLINK_DISABLE_DEVICE_TYPE;
extern NSString *const SETTING_FULLLINK_DISABLE_SIGTHREAD_PRI;
extern NSString *const SETTING_FULLLINK_DISABLE_FILE_OR_DIRECTORY_NAME;
// tts
extern NSString *const SETTING_TTS;
extern NSString *const SETTING_TTS_ONLINE_LANGUAGE;
extern NSString *const SETTING_TTS_OFFLINE_LANGUAGE;
extern NSString *const SETTING_TTS_ENABLE_PLAYER;
extern NSString *const SETTING_TTS_ENABLE_DUMP;
extern NSString *const SETTING_TTS_ENABLE_DATA_CALLBACK;
extern NSString *const SETTING_TTS_ENABLE_CACHE;
extern NSString *const SETTING_TTS_WITH_INTENT;
extern NSString *const SETTING_TTS_LIMIT_CPU_USAGE;
extern NSString *const SETTING_TTS_TEXT_TYPE;
extern NSString *const SETTING_TTS_WORK_MODE;
extern NSString *const SETTING_TTS_SPEAK_SPEED;
extern NSString *const SETTING_TTS_AUDIO_VOLUME;
extern NSString *const SETTING_TTS_AUDIO_PITCH;
extern NSString *const SETTING_TTS_SAMPLE_RATE;
extern NSString *const SETTING_TTS_EMOTION;
extern NSString *const SETTING_TTS_MODEL_NAME;
extern NSString *const SETTING_TTS_SILENCE_DURATION;
extern NSString *const SETTING_TTS_OFFLINE_RESOURCE_FORMAT;
extern NSString *const SETTING_TTS_LICENSE_NAME;
extern NSString *const SETTING_TTS_LICENSE_BUSI_ID;
extern NSString *const SETTING_TTS_BACKEND_CLUSTER;
extern NSString *const SETTING_TTS_SILENCE_DURATION;
extern NSString *const SETTING_TTS_USE_VOICECLONE_VOICE;
// voiceclone
extern NSString *const SETTING_VOICECLONE;
extern NSString *const SETTING_VOICECLONE_ADDRESS;
extern NSString *const SETTING_VOICECLONE_STREAM_ADDRESS;
extern NSString *const SETTING_VOICECLONE_UID;
extern NSString *const SETTING_VOICECLONE_QUERY_UIDS;
extern NSString *const SETTING_VOICECLONE_VOICE_TYPE;
extern NSString *const SETTING_VOICECLONE_GENDER;
extern NSString *const SETTING_VOICECLONE_TASKID;
// voiceconv
extern NSString *const SETTING_VOICECONV;
extern NSString *const SETTING_VOICECONV_RESULT_SAMPLE_RATE;
extern NSString *const SETTING_VOICECONV_ENABLE_RECORD_DUMP;
extern NSString *const SETTING_VOICECONV_ENABLE_RESULT_DUMP;
extern NSString *const SETTING_VOICECONV_REQUEST_INTERVAL;
// dialog
extern NSString *const SETTING_DIALOG;
extern NSString *const SETTING_DIALOG_ID;
extern NSString *const SETTING_DIALOG_ROLE;
extern NSString *const SETTING_DIALOG_CLOTHES_TYPE;
extern NSString *const SETTING_DIALOG_TTA_VOICE_TYPE;
// vad
extern NSString *const SETTING_VAD;
extern NSString *const SETTING_VAD_RECORDER_SAVE;
extern NSString *const SETTING_VAD_HEAD_SILENCE_THRESHOLD;
extern NSString *const SETTING_VAD_TAIL_SILENCE_THRESHOLD;
// au
extern NSString *const SETTING_AU;
extern NSString *const SETTING_AU_ABILITY;
extern NSString *const SETTING_AU_RECORDER_SAVE;
extern NSString *const SETTING_AU_PROCESS_TIMEOUT;
extern NSString *const SETTING_AU_AUDIO_PACKET_DURATION;
extern NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL;
#pragma mark - SETTING_HELPER
@interface SettingsHelper : NSObject
+ (instancetype)shareInstance;
- (Settings*)getSettings:(NSString*)engine;
@end
NS_ASSUME_NONNULL_END
//
// SettingsHelper.m
// SpeechDemo
//
// Created by bytedance on 2020/9/9.
// Copyright © 2020 fengkai.0518. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SettingsHelper.h"
#import "SensitiveDefines.h"
@interface SettingsHelper()
@property (strong, nonatomic) Settings* asrSettings;
@property (strong, nonatomic) Settings* asrOfflineSettings;
@property (strong, nonatomic) Settings* captSettings;
@property (strong, nonatomic) Settings* fulllinkSettings;
@property (strong, nonatomic) Settings* ttsSettings;
@property (strong, nonatomic) Settings* voiceCloneSettings;
@property (strong, nonatomic) Settings* voiceConvSettings;
@property (strong, nonatomic) Settings* dialogSettings;
@property (strong, nonatomic) Settings* vadSettings;
@property (strong, nonatomic) Settings* auSettings;
@end
@implementation SettingsHelper
#pragma mark - SETTING_KEY
// common
NSString *const SETTING_COMMON = @"Common";
NSString *const SETTING_APPID = @"AppID";
NSString *const SETTING_TOKEN = @"Token";
NSString *const SETTING_CLUSTER = @"Cluster";
NSString *const SETTING_ADDRESS = @"Address";
NSString *const SETTING_URI = @"Uri";
NSString *const SETTING_VOICE = @"Voice";
NSString *const SETTING_VOICE_TYPE = @"Voice Type";
NSString *const SETTING_ONLINE_VOICE = @"Online Voice";
NSString *const SETTING_ONLINE_VOICE_TYPE = @"Online Voice Type";
NSString *const SETTING_OFFLINE_VOICE = @"Offline Voice";
NSString *const SETTING_OFFLINE_VOICE_TYPE = @"Offline Voice Type";
NSString *const SETTING_GET_VOLUME = @"Get Volume";
NSString *const SETTING_RECORD_TYPE = @"Record Type";
NSString *const SETTING_RECORD_SAVE = @"Record Save";
NSString *const SETTING_RECORD_FILE_TYPE = @"Record File Type";
NSString *const SETTING_SAMPLE_RATE = @"Sample Rate";
NSString *const SETTING_CHANNEL = @"Channel";
NSString *const SETTING_ENABLE_AEC = @"Enable Aec";
NSString *const SETTING_RESTART_AUDIO_SESSION_ENABLE = @"Restart AudioSession";
NSString *const SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE = @"Resume Others Interrupted Playback";
NSString *const SETTING_AUTHENTICATION_TYPE = @"Authentication Type";
NSString *const SETTING_BUSINESS_KEY = @"Business Key";
NSString *const SETTING_AUTHENTICATE_SECRET = @"Authenticate Secret";
NSString *const SETTING_AUDIO_FADEOUT_DURATION = @"Audio Fade Out Duration";
NSString *const SETTING_VAD_MAX_SPEECH_DURATION = @"Vad Max Speech Duration";
NSString *const SETTING_VAD_MAX_MUSIC_DURATION = @"Vad Max Music Duration";
NSString *const SETTING_STREAM_PACKAGE_DURATION = @"Stream Package Duration";
// asr
NSString *const SETTING_ASR = @"Asr";
NSString *const SETTING_ASR_WORK_MODE = @"Asr Work Mode";
NSString *const SETTING_ASR_SCENARIO_TYPE = @"Asr Scenario Type";
NSString *const SETTING_ASR_RECORDER_SAVE = @"Asr Recorder Save";
NSString *const SETTING_ASR_ENABLE_DDC = @"Asr Enable Ddc";
NSString *const SETTING_ASR_ENABLE_ITN = @"Asr Enable Itn";
NSString *const SETTING_ASR_ENABLE_NLU_PUNC = @"Asr Enable nlu punctuation";
NSString *const SETTING_ASR_DISABLE_END_PUNC = @"asr_disable_end_punc";
NSString *const SETTING_ASR_KEEP_RECORDING = @"Asr Enable Keep Recording";
NSString *const SETTING_ASR_HOTWORDS = @"Asr HotWords";
NSString *const SETTING_ASR_CORRECTWORDS = @"Asr CorrectWords";
NSString *const SETTING_ASR_VAD_START_SILENCE_TIME = @"Asr Start Silence Time";
NSString *const SETTING_ASR_VAD_END_SILENCE_TIME = @"Asr VAD Silence Time";
NSString *const SETTING_ASR_VAD_MODE = @"Asr VAD Mode";
NSString *const SETTING_ASR_RESULT_TYPE = @"Asr Result Type";
NSString *const SETTING_ASR_MAX_RETRY_TIMES = @"Asr Max Retry Times";
NSString *const SETTING_ASR_SHOW_LANGUAGE = @"Asr Show Language";
NSString *const SETTING_ASR_LANGUAGE = @"Asr Language";
NSString *const SETTING_ASR_AUTO_STOP = @"Asr Auto Stop";
// capt
NSString *const SETTING_CAPT = @"Capt";
NSString *const SETTING_CAPT_RECORDER_SAVE = @"Capt Recorder Save";
NSString *const SETTING_CAPT_STREAMING_MODE = @"Capt Streaming Mode";
NSString *const SETTING_CAPT_CORE_TYPE = @"Capt Core Type";
NSString *const SETTING_CAPT_DIFFICULTY_LEVEL = @"Capt Difficulty Level";
// fulllink
NSString *const SETTING_FULLLINK = @"Fulllink";
NSString *const SETTING_FULLLINK_ENGINE_TYPE = @"Fulllink Engine Type";
NSString *const SETTING_FULLLINK_WAKEUP_WORDS = @"Fulllink Wakeup Words";
NSString *const SETTING_FULLLINK_ENABLE_RECORDER_DUMP = @"Fulllink Enable Recorder Dump";
NSString *const SETTING_FULLLINK_ENABLE_KWS_DUMP = @"Fulllink Enable Kws Dump";
NSString *const SETTING_FULLLINK_WAKEUP_MODE = @"Fulllink Wakeup Mode";
NSString *const SETTING_FULLLINK_ONLY_ASR = @"Fulllink Only Asr";
NSString *const SETTING_FULLLINK_DISABLE_TTS = @"Fulllink Disable Tts";
NSString *const SETTING_FULLLINK_DISABLE_SIGNAL = @"Fulllink Disable Signal";
NSString *const SETTING_FULLLINK_DISABLE_DEVICE_TYPE = @"Fulllink Device Type";
NSString *const SETTING_FULLLINK_DISABLE_SIGTHREAD_PRI = @"Fulllink Disable SigThread Pri";
NSString *const SETTING_FULLLINK_DISABLE_FILE_OR_DIRECTORY_NAME = @"Fulllink Disable File Or Directory Name";
// tts
NSString *const SETTING_TTS = @"Tts";
NSString *const SETTING_TTS_ONLINE_LANGUAGE = @"Tts online Language";
NSString *const SETTING_TTS_EMOTION = @"Tts emotion";
NSString *const SETTING_TTS_OFFLINE_LANGUAGE = @"Tts offline Language";
NSString *const SETTING_TTS_ENABLE_PLAYER = @"Tts Enable Player";
NSString *const SETTING_TTS_ENABLE_DUMP = @"Tts Enable Dump";
NSString *const SETTING_TTS_ENABLE_DATA_CALLBACK = @"Tts Enable Data Callback";
NSString *const SETTING_TTS_ENABLE_CACHE = @"Tts Enable Cache";
NSString *const SETTING_TTS_WITH_INTENT = @"Tts With Intent Predication";
NSString *const SETTING_TTS_LIMIT_CPU_USAGE = @"Tts Limit Cpu Usage";
NSString *const SETTING_TTS_TEXT_TYPE = @"Tts Text Type";
NSString *const SETTING_TTS_WORK_MODE = @"Tts Synthesis Mode";
NSString *const SETTING_TTS_SPEAK_SPEED = @"Tts Speak Speed";
NSString *const SETTING_TTS_AUDIO_VOLUME = @"Tts Audio Volume";
NSString *const SETTING_TTS_AUDIO_PITCH = @"Tts Audio Pitch";
NSString *const SETTING_TTS_SAMPLE_RATE = @"Tts Sample Rate";
NSString *const SETTING_TTS_MODEL_NAME = @"Tts Model Name";
NSString *const SETTING_TTS_LICENSE_NAME = @"Tts License Name";
NSString *const SETTING_TTS_LICENSE_BUSI_ID = @"Tts Busi Id";
NSString *const SETTING_TTS_BACKEND_CLUSTER = @"Backend Cluster";
NSString *const SETTING_TTS_USE_VOICECLONE_VOICE = @"Tts Use VoiceClone Voice";
NSString *const SETTING_TTS_SILENCE_DURATION = @"Tts Silence Duration";
NSString *const SETTING_TTS_OFFLINE_RESOURCE_FORMAT = @"TTS Offline Model Format";
// voiceclone
NSString *const SETTING_VOICECLONE = @"VoiceClone";
NSString *const SETTING_VOICECLONE_ADDRESS = @"VoiceClone Address";
NSString *const SETTING_VOICECLONE_STREAM_ADDRESS = @"VoiceClone Stream Address";
NSString *const SETTING_VOICECLONE_UID = @"VoiceClone Uid";
NSString *const SETTING_VOICECLONE_QUERY_UIDS = @"VoiceClone Query Uids";
NSString *const SETTING_VOICECLONE_VOICE_TYPE = @"VoiceClone Voice Type";
NSString *const SETTING_VOICECLONE_GENDER = @"VoiceClone Gender (Is Female)";
NSString *const SETTING_VOICECLONE_TASKID = @"VoiceClone Taskid";
// voiceconv
NSString *const SETTING_VOICECONV = @"VoiceConv";
NSString *const SETTING_VOICECONV_RESULT_SAMPLE_RATE = @"VoiceConv Result Sample Rate";
NSString *const SETTING_VOICECONV_ENABLE_RECORD_DUMP = @"VoiceConv Enable Record Dump";
NSString *const SETTING_VOICECONV_ENABLE_RESULT_DUMP = @"VoiceConv Enable Result Dump";
NSString *const SETTING_VOICECONV_REQUEST_INTERVAL = @"VoiceConv Request Interval (Unit: ms)";
// dialog
NSString *const SETTING_DIALOG = @"Dialog";
NSString *const SETTING_DIALOG_ID = @"Dialog id";
NSString *const SETTING_DIALOG_ROLE = @"Dialog role";
NSString *const SETTING_DIALOG_CLOTHES_TYPE = @"Dialog clothes type";
NSString *const SETTING_DIALOG_TTA_VOICE_TYPE = @"Dialog tta voice type";
// vad
NSString *const SETTING_VAD = @"Vad";
NSString *const SETTING_VAD_RECORDER_SAVE = @"Vad Recorder Save";
NSString *const SETTING_VAD_HEAD_SILENCE_THRESHOLD = @"Vad Head silence Threshold";
NSString *const SETTING_VAD_TAIL_SILENCE_THRESHOLD = @"Vad Tail silence Threshold";
// au
NSString *const SETTING_AU = @"Au";
NSString *const SETTING_AU_ABILITY = @"Au Ability";
NSString *const SETTING_AU_RECORDER_SAVE = @"Au Recorder Save";
NSString *const SETTING_AU_PROCESS_TIMEOUT = @"Au Process Timeout";
NSString *const SETTING_AU_AUDIO_PACKET_DURATION = @"Au Audio Packet Duration";
NSString *const SETTING_AU_EMPTY_PACKET_INTERVAL = @"Au Empty Packet Interval";
#pragma mark - SETTING_HINT
static NSString *const SETTING_HINT_CLUSTER = @"Cluster";
static NSString *const SETTING_HINT_BACKEND_CLUSTER = @"Backend Cluster";
static NSString *const SETTING_HINT_ADDRESS = @"Address";
static NSString *const SETTING_HINT_URI = @"Uri";
static NSString *const SETTING_HINT_VOICE = @"Voice";
static NSString *const SETTING_HINT_VOICE_TYPE = @"Voice Type";
static NSString *const SETTING_HINT_ONLINE_VOICE = @"Online Voice";
static NSString *const SETTING_HINT_ONLINE_VOICE_TYPE = @"Online Voice Type";
static NSString *const SETTING_HINT_OFFLINE_VOICE = @"Offline Voice";
static NSString *const SETTING_HINT_OFFLINE_VOICE_TYPE = @"Offline Voice Type";
static NSString *const SETTING_HINT_TTS_ONLINE_LANGUAGE = @"Tts online Language";
static NSString *const SETTING_HINT_TTS_EMOTION = @"Tts emotion";
static NSString *const SETTING_HINT_TTS_OFFLINE_LANGUAGE = @"Tts offline Language";
static NSString *const SETTING_HINT_DIFFICULTY_LEVEL = @"Support 1,2,3";
static NSString *const SETTING_HINT_VOICECLONE_UID = @"VoiceClone Uid";
static NSString *const SETTING_HINT_VOICECLONE_QUERY_UIDS = @"VoiceClone Query Uids";
static NSString *const SETTING_HINT_VOICECLONE_VOICE_TYPE = @"VoiceClone Voice Type";
static NSString *const SETTING_HINT_BUSINESS_KEY = @"Business Key";
static NSString *const SETTING_HINT_AUTHENTICATE_SECRET = @"Authenticate Secret";
static NSString *const SETTING_HINT_TTS_LICENSE_NAME = @"Input license name";
static NSString *const SETTING_HINT_TTS_LICENSE_BUSI_ID = @"Input busi id";
static NSString *const SETTING_HINT_TTS_SAMPLE_RATE = @"Input tts sample rate";
static NSString *const SETTING_HINT_TTS_MODEL_NAME = @"Input Tts Model Name";
static NSString *const SETTING_HINT_MAX_CACHE_NUM = @"Input max number of client audio cache, such as 100.";
static NSString *const SETTING_HINT_TTS_CACHE_RENEWAL_DURATION = @"Input cache renewal duration, unit:ms";
static NSString *const SETTING_HINT_DIALOG_ID = @"Dialog id";
static NSString *const SETTING_HINT_DIALOG_ROLE = @"Dialog role";
static NSString *const SETTING_HINT_DIALOG_CLOTHES_TYPE = @"Dialog clothes type";
static NSString *const SETTING_HINT_DIALOG_TTA_VOICE_TYPE = @"Dialog tta voice type";
#pragma mark - SETTING_OPTIONS
static NSArray* SETTING_OPTIONS_RECORD_TYPE(void) {
return @[@"Recorder", @"File", @"Stream"];
}
static NSArray* SETTING_OPTIONS_RECORD_FILE_TYPE(void) {
return @[@"Wav", @"Aac"];
}
static NSArray* SETTING_OPTIONS_ASR_SCENARIO_TYPE(void) {
return @[@"OneSentence", @"Streaming"];
}
static NSArray* SETTING_OPTIONS_ASR_RESULT_TYPE(void) {
return @[@"full", @"single"];
}
static NSArray* SETTING_OPTIONS_CAPT_CORE_TYPE(void) {
return @[@"English sentence score", @"English word score", @"English word pronounce", @"Chinese sentence raw"];
}
static NSArray* SETTING_OPTIONS_ASR_WORK_MODE(void) {
return @[@"Online", @"Offline"];
}
static NSArray* SETTING_OPTIONS_FULLLINK_ENGINE_TYPE(void) {
return @[@"FULLLINK LITE", @"FULLLINK"];
}
static NSArray* SETTING_OPTIONS_FULLLINK_WAKEUP_WORDS(void) {
return @[@"大力大力(only)", @"大力大力(大力同学)", @"大力同学(大力大力)", @"大力同学(only)"];
}
static NSArray* SETTING_OPTIONS_FULLLINK_WAKEUP_MODE(void) {
return @[@"normal", @"disable wakeup", @"night mode"];
}
static NSArray* SETTING_OPTIONS_TTS_TEXT_TYPE(void) {
return @[@"Plain", @"SSML", @"Json"];
}
static NSArray* SETTING_OPTIONS_TTS_WORK_MODE(void) {
return @[@"Online", @"Offline", @"Both", @"Alternate"];
}
static NSArray* SETTING_OPTIONS_TTS_OFFLINE_RESOURCE_FORMAT(void) {
return @[@"SingleVoice", @"MultipleVoice"];
}
static NSArray* SETTING_OPTIONS_AUTHENTICATION_TYPE(void) {
return @[@"Pre Bind", @"Late Bind"];
}
static NSArray* SETTING_OPTIONS_AU_ABILITY(void) {
return @[@"ASR", @"MUSIC", @"ASR+MUSIC"];
}
#pragma mark - Setting Init
+ (instancetype)shareInstance {
static SettingsHelper* sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
// Asr settings
sharedInstance.asrSettings = [Settings build];
[sharedInstance.asrSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_APPID val:SDEF_APPID hint:@""],
[SettingItem buildString:SETTING_TOKEN val:SDEF_TOKEN hint:@""],
[SettingItem buildString:SETTING_CLUSTER val:SDEF_ASR_DEFAULT_CLUSTER hint:SETTING_HINT_CLUSTER],
[SettingItem buildString:SETTING_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:SETTING_HINT_ADDRESS],
[SettingItem buildString:SETTING_URI val:SDEF_ASR_DEFAULT_URI hint:SETTING_HINT_URI],
[SettingItem buildBool:SETTING_GET_VOLUME val:false hint:@""],
[SettingItem buildInt:SETTING_SAMPLE_RATE val:16000 hint:@""],
[SettingItem buildInt:SETTING_CHANNEL val:1 hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_RECORD_SAVE val:false hint:@""],
[SettingItem buildOptions:SETTING_RECORD_FILE_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_FILE_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_RESTART_AUDIO_SESSION_ENABLE val:false hint:@""],
[SettingItem buildBool:SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE val:false hint:@""],
[SettingItem buildInt:SETTING_VAD_MAX_SPEECH_DURATION val:60000 hint:@""],
// asr
[SettingItem buildGroup:SETTING_ASR val:@"" hint:@""],
[SettingItem buildOptions:SETTING_ASR_WORK_MODE val:[SettingOptions build:SETTING_OPTIONS_ASR_WORK_MODE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_ASR_RECORDER_SAVE val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_DDC val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_ITN val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_NLU_PUNC val:true hint:@""],
[SettingItem buildBool:SETTING_ASR_DISABLE_END_PUNC val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_KEEP_RECORDING val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_SHOW_LANGUAGE val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_AUTO_STOP val:false hint:@""],
[SettingItem buildString:SETTING_ASR_LANGUAGE val:@"en-US" hint:@""],
[SettingItem buildString:SETTING_ASR_HOTWORDS val:@"{\"hotwords\":[{\"word\":\"过秦论\",\"scale\":2.0}]}" hint:@""],
[SettingItem buildString:SETTING_ASR_CORRECTWORDS val:@"{\"古爱玲\":\"谷爱凌\",\"古埃宁\":\"谷爱凌\",\"谷爱玲\":\"谷爱凌\",\"谷埃宁\":\"谷爱凌\"}" hint:@""],
[SettingItem buildOptions:SETTING_ASR_RESULT_TYPE val:[SettingOptions build:SETTING_OPTIONS_ASR_RESULT_TYPE() choose:0] hint:@""],
[SettingItem buildInt:SETTING_ASR_MAX_RETRY_TIMES val:0 hint:@""],
]];
// Asr offline settings
sharedInstance.asrOfflineSettings = [Settings build];
[sharedInstance.asrOfflineSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_APPID val:SDEF_APPID hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
[SettingItem buildInt:SETTING_VAD_MAX_SPEECH_DURATION val:15000 hint:@""],
[SettingItem buildInt:SETTING_STREAM_PACKAGE_DURATION val:20000 hint:@""],
// asr
[SettingItem buildGroup:SETTING_ASR val:@"" hint:@""],
[SettingItem buildBool:SETTING_ASR_RECORDER_SAVE val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_ITN val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_SHOW_LANGUAGE val:false hint:@""],
]];
// Capt settings
sharedInstance.captSettings = [Settings build];
[sharedInstance.captSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_CLUSTER val:SDEF_CAPT_DEFAULT_CLUSTER hint:SETTING_HINT_CLUSTER],
[SettingItem buildString:SETTING_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:SETTING_HINT_ADDRESS],
[SettingItem buildString:SETTING_URI val:@"" hint:SETTING_HINT_URI],
[SettingItem buildString:SETTING_APPID val:SDEF_APPID hint:@""],
[SettingItem buildString:SETTING_TOKEN val:SDEF_APPID hint:@""],
[SettingItem buildBool:SETTING_GET_VOLUME val:false hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_ENABLE_AEC val:false hint:@""],
[SettingItem buildBool:SETTING_RESTART_AUDIO_SESSION_ENABLE val:false hint:@""],
[SettingItem buildBool:SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE val:false hint:@""],
[SettingItem buildInt:SETTING_VAD_MAX_SPEECH_DURATION val:15000 hint:@""],
// capt
[SettingItem buildGroup:SETTING_CAPT val:@"" hint:@""],
[SettingItem buildBool:SETTING_CAPT_RECORDER_SAVE val:false hint:@""],
[SettingItem buildBool:SETTING_CAPT_STREAMING_MODE val:false hint:@""],
[SettingItem buildOptions:SETTING_CAPT_CORE_TYPE val:[SettingOptions build:SETTING_OPTIONS_CAPT_CORE_TYPE() choose:0] hint:@""],
[SettingItem buildInt:SETTING_CAPT_DIFFICULTY_LEVEL val:2 hint:SETTING_HINT_DIFFICULTY_LEVEL],
]];
// Fulllink settings
sharedInstance.fulllinkSettings = [Settings build];
[sharedInstance.fulllinkSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_CLUSTER val:@"" hint:SETTING_HINT_CLUSTER],
[SettingItem buildString:SETTING_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:SETTING_HINT_ADDRESS],
[SettingItem buildBool:SETTING_GET_VOLUME val:false hint:@""],
[SettingItem buildInt:SETTING_SAMPLE_RATE val:16000 hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_ENABLE_AEC val:false hint:@""],
[SettingItem buildBool:SETTING_RESTART_AUDIO_SESSION_ENABLE val:false hint:@""],
[SettingItem buildBool:SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE val:false hint:@""],
// fulllink
[SettingItem buildGroup:SETTING_FULLLINK val:@"" hint:@""],
[SettingItem buildOptions:SETTING_FULLLINK_ENGINE_TYPE val:[SettingOptions build:SETTING_OPTIONS_FULLLINK_ENGINE_TYPE() choose:0] hint:@""],
[SettingItem buildOptions:SETTING_FULLLINK_WAKEUP_WORDS val:[SettingOptions build:SETTING_OPTIONS_FULLLINK_WAKEUP_WORDS() choose:0] hint:@""],
[SettingItem buildBool:SETTING_FULLLINK_ENABLE_RECORDER_DUMP val:false hint:@""],
[SettingItem buildBool:SETTING_FULLLINK_ENABLE_KWS_DUMP val:false hint:@""],
[SettingItem buildOptions:SETTING_FULLLINK_WAKEUP_MODE val:[SettingOptions build:SETTING_OPTIONS_FULLLINK_WAKEUP_MODE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_FULLLINK_ONLY_ASR val:false hint:@""],
[SettingItem buildBool:SETTING_FULLLINK_DISABLE_TTS val:false hint:@""],
[SettingItem buildBool:SETTING_FULLLINK_DISABLE_SIGNAL val:false hint:@""],
[SettingItem buildInt:SETTING_FULLLINK_DISABLE_SIGTHREAD_PRI val:-10 hint:@""],
[SettingItem buildString:SETTING_FULLLINK_DISABLE_FILE_OR_DIRECTORY_NAME val:@"" hint:@""],
]];
// Tts settings
sharedInstance.ttsSettings = [Settings build];
[sharedInstance.ttsSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_CLUSTER val:SDEF_TTS_DEFAULT_CLUSTER hint:SETTING_HINT_CLUSTER],
[SettingItem buildString:SETTING_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:SETTING_HINT_ADDRESS],
[SettingItem buildString:SETTING_URI val:SDEF_TTS_DEFAULT_URI hint:SETTING_HINT_URI],
[SettingItem buildString:SETTING_ONLINE_VOICE val:SDEF_TTS_DEFAULT_ONLINE_VOICE hint:SETTING_HINT_ONLINE_VOICE],
[SettingItem buildString:SETTING_ONLINE_VOICE_TYPE val:SDEF_TTS_DEFAULT_ONLINE_VOICE_TYPE hint:SETTING_HINT_ONLINE_VOICE_TYPE],
[SettingItem buildString:SETTING_OFFLINE_VOICE val:SDEF_TTS_DEFAULT_OFFLINE_VOICE hint:SETTING_HINT_OFFLINE_VOICE],
[SettingItem buildString:SETTING_OFFLINE_VOICE_TYPE val:SDEF_TTS_DEFAULT_OFFLINE_VOICE_TYPE hint:SETTING_HINT_OFFLINE_VOICE_TYPE],
[SettingItem buildOptions:SETTING_AUTHENTICATION_TYPE val:[SettingOptions build:SETTING_OPTIONS_AUTHENTICATION_TYPE() choose:0] hint:@""],
[SettingItem buildString:SETTING_TTS_LICENSE_NAME val:SDEF_LICENSE_NAME hint:SETTING_HINT_TTS_LICENSE_NAME],
[SettingItem buildString:SETTING_TTS_LICENSE_BUSI_ID val:SDEF_LICENSE_BUSI_ID hint:SETTING_HINT_TTS_LICENSE_BUSI_ID],
[SettingItem buildString:SETTING_BUSINESS_KEY val:SDEF_BUSINESS_KEY hint:SETTING_HINT_BUSINESS_KEY],
[SettingItem buildString:SETTING_AUTHENTICATE_SECRET val:SDEF_SECRET hint:SETTING_HINT_AUTHENTICATE_SECRET],
[SettingItem buildInt:SETTING_AUDIO_FADEOUT_DURATION val:0 hint:@""],
// tts
[SettingItem buildGroup:SETTING_TTS val:@"" hint:@""],
[SettingItem buildOptions:SETTING_TTS_WORK_MODE val:[SettingOptions build:SETTING_OPTIONS_TTS_WORK_MODE() choose:0] hint:@""],
[SettingItem buildOptions:SETTING_TTS_TEXT_TYPE val:[SettingOptions build:SETTING_OPTIONS_TTS_TEXT_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_TTS_ENABLE_PLAYER val:true hint:@""],
[SettingItem buildBool:SETTING_TTS_ENABLE_DUMP val:false hint:@""],
[SettingItem buildBool:SETTING_TTS_ENABLE_DATA_CALLBACK val:false hint:@""],
[SettingItem buildInt:SETTING_TTS_SILENCE_DURATION val:0 hint:@""],
[SettingItem buildInt:SETTING_TTS_SPEAK_SPEED val:10 hint:@""],
[SettingItem buildInt:SETTING_TTS_AUDIO_VOLUME val:10 hint:@""],
[SettingItem buildInt:SETTING_TTS_AUDIO_PITCH val:10 hint:@""],
[SettingItem buildInt:SETTING_TTS_SAMPLE_RATE val:16000 hint:SETTING_HINT_TTS_SAMPLE_RATE],
[SettingItem buildBool:SETTING_TTS_ENABLE_CACHE val:false hint:@""],
[SettingItem buildBool:SETTING_TTS_WITH_INTENT val:false hint:@""],
[SettingItem buildString:SETTING_TTS_ONLINE_LANGUAGE val:SDEF_TTS_DEFAULT_ONLINE_LANGUAGE hint:SETTING_HINT_TTS_ONLINE_LANGUAGE],
[SettingItem buildString:SETTING_TTS_EMOTION val:@"" hint:SETTING_HINT_TTS_EMOTION],
[SettingItem buildBool:SETTING_TTS_USE_VOICECLONE_VOICE val:false hint:@""],
[SettingItem buildString:SETTING_TTS_BACKEND_CLUSTER val:@"demo_test" hint:SETTING_HINT_BACKEND_CLUSTER],
[SettingItem buildOptions:SETTING_TTS_OFFLINE_RESOURCE_FORMAT val:[SettingOptions build:SETTING_OPTIONS_TTS_OFFLINE_RESOURCE_FORMAT() choose:0] hint:@""],
[SettingItem buildString:SETTING_TTS_OFFLINE_LANGUAGE val:SDEF_TTS_DEFAULT_OFFLINE_LANGUAGE hint:SETTING_HINT_TTS_OFFLINE_LANGUAGE],
[SettingItem buildString:SETTING_TTS_MODEL_NAME val:@"aispeech_tts" hint:SETTING_HINT_TTS_MODEL_NAME],
[SettingItem buildBool:SETTING_TTS_LIMIT_CPU_USAGE val:false hint:@""],
]];
// VoiceClone settings
sharedInstance.voiceCloneSettings = [Settings build];
[sharedInstance.voiceCloneSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildInt:SETTING_SAMPLE_RATE val:44100 hint:@""],
[SettingItem buildString:SETTING_APPID val:SDEF_APPID hint:@""],
[SettingItem buildString:SETTING_TOKEN val:SDEF_APPID hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
// voiceclone
[SettingItem buildGroup:SETTING_VOICECLONE val:@"" hint:@""],
[SettingItem buildString:SETTING_VOICECLONE_ADDRESS val:SDEF_DEFAULT_HTTP_ADDRESS hint:@""],
[SettingItem buildString:SETTING_VOICECLONE_STREAM_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:@""],
[SettingItem buildString:SETTING_VOICECLONE_UID val:SDEF_UID hint:SETTING_HINT_VOICECLONE_UID],
[SettingItem buildString:SETTING_VOICECLONE_QUERY_UIDS val:SDEF_VOICECLONE_DEFAULT_UIDS hint:SETTING_HINT_VOICECLONE_QUERY_UIDS],
[SettingItem buildString:SETTING_VOICECLONE_VOICE_TYPE val:@"" hint:SETTING_HINT_VOICECLONE_VOICE_TYPE],
[SettingItem buildBool:SETTING_VOICECLONE_GENDER val:false hint:@""],
[SettingItem buildInt:SETTING_VOICECLONE_TASKID val:SDEF_VOICECLONE_DEFAULT_TASK_ID hint:@""],
]];
// VoiceConv settings
sharedInstance.voiceConvSettings = [Settings build];
[sharedInstance.voiceConvSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_VOICE val:SDEF_VOICECONV_DEFAULT_VOICE hint:SETTING_HINT_VOICE],
[SettingItem buildString:SETTING_VOICE_TYPE val:SDEF_VOICECONV_DEFAULT_VOICE_TYPE hint:SETTING_HINT_VOICE_TYPE],
[SettingItem buildBool:SETTING_GET_VOLUME val:false hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
// voiceconv
[SettingItem buildGroup:SETTING_VOICECONV val:@"" hint:@""],
[SettingItem buildInt:SETTING_VOICECONV_RESULT_SAMPLE_RATE val:24000 hint:@""],
[SettingItem buildBool:SETTING_VOICECONV_ENABLE_RECORD_DUMP val:true hint:@""],
[SettingItem buildBool:SETTING_VOICECONV_ENABLE_RESULT_DUMP val:true hint:@""],
[SettingItem buildInt:SETTING_VOICECONV_REQUEST_INTERVAL val:200 hint:@""],
]];
// Dialog settings
sharedInstance.dialogSettings = [Settings build];
[sharedInstance.dialogSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_APPID val:SDEF_APPID hint:@""],
[SettingItem buildString:SETTING_TOKEN val:SDEF_TOKEN hint:@""],
[SettingItem buildString:SETTING_ADDRESS val:SDEF_DEFAULT_ADDRESS hint:SETTING_HINT_ADDRESS],
[SettingItem buildString:SETTING_URI val:SDEF_DIALOG_DEFAULT_URI hint:SETTING_HINT_URI],
// dialog
[SettingItem buildGroup:SETTING_DIALOG val:@"" hint:@""],
[SettingItem buildString:SETTING_DIALOG_ID val:SDEF_DIALOG_DEFAULT_ID hint:SETTING_HINT_DIALOG_ID],
[SettingItem buildString:SETTING_DIALOG_ROLE val:SDEF_DIALOG_DEFAULT_ROLE hint:SETTING_HINT_DIALOG_ROLE],
[SettingItem buildString:SETTING_DIALOG_CLOTHES_TYPE val:SDEF_DIALOG_DEFAULT_CLOTHES_TYPE hint:SETTING_HINT_DIALOG_CLOTHES_TYPE],
[SettingItem buildString:SETTING_DIALOG_TTA_VOICE_TYPE val:SDEF_DIALOG_DEFAULT_TTA_VOICE_TYPE hint:SETTING_HINT_DIALOG_TTA_VOICE_TYPE],
]];
// Vad settings
sharedInstance.vadSettings = [Settings build];
[sharedInstance.vadSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildBool:SETTING_GET_VOLUME val:false hint:@""],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
[SettingItem buildBool:SETTING_RESTART_AUDIO_SESSION_ENABLE val:false hint:@""],
[SettingItem buildBool:SETTING_RESUME_OTHERS_INTERRUPTED_PLAYBACK_ENABLE val:false hint:@""],
// vad
[SettingItem buildGroup:SETTING_VAD val:@"" hint:@""],
[SettingItem buildBool:SETTING_VAD_RECORDER_SAVE val:false hint:@""],
[SettingItem buildInt:SETTING_VAD_HEAD_SILENCE_THRESHOLD val:4000 hint:@""],
[SettingItem buildInt:SETTING_VAD_TAIL_SILENCE_THRESHOLD val:2000 hint:@""],
]];
// Au settings
sharedInstance.auSettings = [Settings build];
[sharedInstance.auSettings registerItems:@[
// common
[SettingItem buildGroup:SETTING_COMMON val:@"" hint:@""],
[SettingItem buildString:SETTING_APPID val:@"vs_tt_input_qa" hint:@""],
[SettingItem buildString:SETTING_TOKEN val:SDEF_TOKEN hint:@""],
[SettingItem buildString:SETTING_CLUSTER val:@"vs_tt_input_qa" hint:SETTING_HINT_CLUSTER],
[SettingItem buildString:SETTING_ADDRESS val:@"wss://speech-maliva.bytedance.com" hint:SETTING_HINT_ADDRESS],
[SettingItem buildString:SETTING_URI val:@"/api/v1/sauc_test" hint:SETTING_HINT_URI],
[SettingItem buildOptions:SETTING_RECORD_TYPE val:[SettingOptions build:SETTING_OPTIONS_RECORD_TYPE() choose:0] hint:@""],
// au
[SettingItem buildGroup:SETTING_AU val:@"" hint:@""],
[SettingItem buildOptions:SETTING_AU_ABILITY val:[SettingOptions build:SETTING_OPTIONS_AU_ABILITY() choose:2] hint:@""],
[SettingItem buildBool:SETTING_AU_RECORDER_SAVE val:false hint:@""],
[SettingItem buildInt:SETTING_AU_PROCESS_TIMEOUT val:3000 hint:@""],
[SettingItem buildInt:SETTING_AU_AUDIO_PACKET_DURATION val:80 hint:@""],
[SettingItem buildInt:SETTING_AU_EMPTY_PACKET_INTERVAL val:500 hint:@""],
[SettingItem buildInt:SETTING_VAD_MAX_SPEECH_DURATION val:60000 hint:@""],
[SettingItem buildInt:SETTING_VAD_MAX_MUSIC_DURATION val:12000 hint:@""],
// asr
[SettingItem buildGroup:SETTING_ASR val:@"" hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_DDC val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_ITN val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_ENABLE_NLU_PUNC val:false hint:@""],
[SettingItem buildBool:SETTING_ASR_SHOW_LANGUAGE val:false hint:@""],
[SettingItem buildString:SETTING_ASR_LANGUAGE val:@"en-US" hint:@""],
[SettingItem buildString:SETTING_ASR_HOTWORDS val:@"{\"hotwords\":[{\"word\":\"过秦论\",\"scale\":\"2.0\"}]}" hint:@""],
[SettingItem buildInt:SETTING_ASR_VAD_START_SILENCE_TIME val:0 hint:@""],
[SettingItem buildInt:SETTING_ASR_VAD_END_SILENCE_TIME val:0 hint:@""],
[SettingItem buildString:SETTING_ASR_VAD_MODE val:@"" hint:@""],
[SettingItem buildOptions:SETTING_ASR_RESULT_TYPE val:[SettingOptions build:SETTING_OPTIONS_ASR_RESULT_TYPE() choose:0] hint:@""],
]];
});
return sharedInstance;
}
@end
//
// SettingsViewController.h
// SpeechDemo
//
// Created by fangweiwei on 2020/2/28.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SettingsViewController : UITableViewController
@property (strong, nonatomic) NSString *viewId;
@end
NS_ASSUME_NONNULL_END
//
// SettingsViewController.m
// SpeechDemo
//
// Created by fangweiwei on 2020/2/28.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#import "SettingsViewController.h"
#import "SettingsHelper.h"
#import "SettingViewDelegate.h"
@interface SettingsViewController () <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITableView *settingTableView;
@property (strong, nonatomic) SettingViewDelegate *settingViewDelegate;
@end
@implementation SettingsViewController
- (void)viewDidLoad {
[super viewDidLoad];
SettingsHelper* settingsInstance = [SettingsHelper shareInstance];
self.settingViewDelegate = [SettingViewDelegate build:[settingsInstance getSettings:self.viewId]];
self.settingTableView.delegate = self.settingViewDelegate;
self.settingTableView.dataSource = self.settingViewDelegate;
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
[segue destinationViewController];
}
@end
//
// SpeechMessageProcessor.h
// SpeechDemo
//
// Created by bytedance on 2022/4/18.
// Copyright © 2022 fangweiwei. All rights reserved.
//
#define SpeechMessageProcessor_h
#import <Foundation/Foundation.h>
#import <SpeechEngineToB/SpeechEngine.h>
@interface CallbackMessage : NSObject
@property (nonatomic, assign) SEMessageType type;
@property (nonatomic, assign) NSData* data;
@end
@protocol SpeechMessageProcessor <NSObject>
- (void)processMessage:(CallbackMessage*)message;
@end
@interface SpeechMessageDispatcher : NSObject <SpeechEngineDelegate>
- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data;
- (instancetype)initWithDelegate:(id<SpeechMessageProcessor>)delegate;
- (void)destroyDispatcher;
@end
//
// SpeechMessageProcessor.m
// SpeechDemo
//
// Created by bytedance on 2022/4/18.
// Copyright © 2022 fangweiwei. All rights reserved.
//
#import "SpeechMessageProcessor.h"
@implementation CallbackMessage
@end
@interface SpeechMessageDispatcher()
// separate thread to process callback message
@property (nonatomic, strong) NSThread *messageProcessThread;
@property (nonatomic, weak) id<SpeechMessageProcessor> messageProcessorDelegate;
@end
@implementation SpeechMessageDispatcher
- (instancetype)init {
return [self initWithDelegate:nil];
}
- (instancetype)initWithDelegate:(id<SpeechMessageProcessor>)delegate {
self = [super init];
if (self) {
self.messageProcessorDelegate = delegate;
self.messageProcessThread = [[NSThread alloc] initWithTarget:self selector:@selector(messageProcessThreadEntryPoint:) object:nil];
if (self.messageProcessThread) {
[self.messageProcessThread start];
} else {
self = nil;
}
}
return self;
}
- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
if (self.messageProcessorDelegate && self.messageProcessThread) {
CallbackMessage* message = [[CallbackMessage alloc] init];
message.type = type;
message.data = data;
[self performSelector:@selector(processMessage:) onThread:self.messageProcessThread withObject:message waitUntilDone:YES];
}
}
- (void)messageProcessThreadEntryPoint:(id)object {
@autoreleasepool {
[[NSThread currentThread] setName:@"SpeechMessageProcessor"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
- (void)processMessage:(CallbackMessage*)message {
if (self.messageProcessorDelegate) {
[self.messageProcessorDelegate processMessage:message];
}
}
- (void) destroyDispatcher {
if (self.messageProcessThread) {
[self.messageProcessThread cancel];
}
}
@end
//
// SpeechMonitor.h
// SpeechDemo
//
// Created by fangweiwei on 2023/3/31.
// Copyright © 2023 fangweiwei. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SpeechMonitor : NSObject
+ (instancetype)shareInstance;
- (void)UploadDelay:(long)delay withEventName:(NSString *)eventName withServiceName:(NSString *)serviceName;
- (void)UploadMetric:(NSDictionary *)metric withServiceName:(NSString *)serviceName;
@end
NS_ASSUME_NONNULL_END
//
// SpeechMonitor.m
// SpeechDemo
//
// Created by fangweiwei on 2023/3/31.
// Copyright © 2023 fangweiwei. All rights reserved.
//
#import "SpeechMonitor.h"
@implementation SpeechMonitor
+ (instancetype)shareInstance {
static SpeechMonitor* sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)UploadDelay:(long)delay withEventName:(NSString *)eventName withServiceName:(NSString *)serviceName {
NSLog(@"Upload delay: %ld.", delay);
NSMutableDictionary *metric = [[NSMutableDictionary alloc] init];
[metric setValue:[NSNumber numberWithLong:delay] forKey:eventName];
[self UploadMetric:metric withServiceName:serviceName];
}
- (void)UploadMetric:(NSDictionary *)metric withServiceName:(NSString *)serviceName {
NSLog(@"%@", metric);
}
@end
//
// StreamRecorder.h
// SpeechDemo
//
// Created by fangweiwei on 2020/9/16.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#define StreamRecorder_H
#import <Foundation/Foundation.h>
#import <SpeechEngineToB/SpeechEngineToB-umbrella.h>
NS_ASSUME_NONNULL_BEGIN
@interface StreamRecorder : NSObject
- (int)getSampleRate;
- (int)getChannel;
- (void)setSpeechEngine:(SpeechEngine *)engine;
- (void)setSpeechEngine:(NSString *) viewId engine:(SpeechEngine *)engine;
- (BOOL)start;
- (void)stop;
@end
NS_ASSUME_NONNULL_END
//
// StreamRecorder.m
// SpeechDemo
//
// Created by fangweiwei on 2020/9/16.
// Copyright © 2020 fangweiwei. All rights reserved.
//
#import "StreamRecorder.h"
#import "SettingsHelper.h"
#import <AVFoundation/AVFoundation.h>
#define INPUT_BUS 1
#define OUTPUT_BUS 0
#define REC_SAMPLE_RATE 44100
#define REC_CHANNEL 1
#define DEFAULT_PACKAGE_DURATION 100
@interface StreamRecorder ()
@property (assign, nonatomic) BOOL initted;
@property (weak, nonatomic) SpeechEngine *curEngine;
@property (weak, nonatomic) NSString *curViewId;
@property (assign, atomic) int16_t* packageData;
@property (assign, nonatomic) int packageSize; // Size in int16_t
@property (assign, nonatomic) int packageTotalSize; // Size in int16_t
@property (assign, nonatomic) int packageDuration; // Unit: milliseconds
@property (strong, nonatomic) dispatch_semaphore_t waitAudioPermission;
@end
AudioUnit audioUnit;
@implementation StreamRecorder
- (instancetype)init
{
self = [super init];
if (self) {
_initted = FALSE;
_waitAudioPermission = dispatch_semaphore_create(0);
}
return self;
}
- (int)getSampleRate {
return REC_SAMPLE_RATE;
}
- (int)getChannel {
return REC_CHANNEL;
}
- (void)setSpeechEngine:(SpeechEngine *)engine {
[self setSpeechEngine: @"" engine: engine];
}
- (void)setSpeechEngine:(NSString *) viewId engine:(SpeechEngine *)engine {
self.curViewId = viewId;
self.curEngine = engine;
}
- (BOOL)start {
if (![self initRemoteIO]) {
return FALSE;
}
@synchronized (self) {
Settings *settings = [[SettingsHelper shareInstance]getSettings:self.curViewId];
self.packageDuration = [settings getInt:SETTING_STREAM_PACKAGE_DURATION def:DEFAULT_PACKAGE_DURATION];
self.packageTotalSize = (int)((long) REC_SAMPLE_RATE * REC_CHANNEL * 16 / 8 * self.packageDuration / 1000 / sizeof(int16_t));
self.packageData = (int16_t*) malloc(self.packageTotalSize * sizeof(int16_t));
self.packageSize = 0;
}
AudioOutputUnitStart(audioUnit);
return TRUE;
}
- (void)stop {
AudioOutputUnitStop(audioUnit);
@synchronized (self) {
if (self.packageData != NULL) {
free(self.packageData);
self.packageData = NULL;
}
self.packageSize = 0;
}
}
- (BOOL)initRemoteIO {
if (self.initted) {
return TRUE;
}
if (!([self checkRecEnvironment] &&
[self initAudioComponent] &&
[self initFormat] &&
[self initAudioProperty] &&
[self initRecordCallback])) {
NSLog(@"Fail to initialize remoteIO!");
AudioComponentInstanceDispose(audioUnit);
return FALSE;
}
AudioUnitInitialize(audioUnit);
self.initted = TRUE;
return TRUE;
}
#pragma mark - callback function
static OSStatus RecordCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mData = NULL;
bufferList.mBuffers[0].mDataByteSize = 0;
OSStatus status = AudioUnitRender(audioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, &bufferList);
if (status != noErr) {
NSLog(@"RecordCallback AudioUnitRender error: %d", (int)status);
} else {
StreamRecorder *recorder = (__bridge StreamRecorder *)(inRefCon);
@synchronized (recorder) {
if (recorder.packageData == NULL) {
return noErr;
}
int16_t *data = (int16_t *)bufferList.mBuffers[0].mData;
int32_t data_size = bufferList.mBuffers[0].mDataByteSize / 2;
while (data_size + recorder.packageSize >= recorder.packageTotalSize) {
// Package buffer is full, feed audio.
int cut_size = recorder.packageTotalSize - recorder.packageSize;
memcpy(recorder.packageData + recorder.packageSize, data, cut_size * sizeof(int16_t));
NSLog(@"Current package size: %d, total package size: %d", recorder.packageSize, recorder.packageTotalSize);
if ([recorder.curEngine feedAudio:recorder.packageData length:recorder.packageTotalSize]) {
NSLog(@"Fail to feed data to engine!");
return -1;
}
recorder.packageSize = 0;
data = data + cut_size;
data_size = data_size - cut_size;
}
memcpy(recorder.packageData + recorder.packageSize, data, data_size * sizeof(int16_t));
recorder.packageSize += data_size;
NSLog(@"Current package size: %d, total package size: %d", recorder.packageSize, recorder.packageTotalSize);
}
}
return noErr;
}
#pragma mark - helper
- (BOOL)checkRecEnvironment {
NSLog(@"check rec environment");
BOOL ret = NO;
__block BOOL hasPermission = YES;
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:@selector(requestRecordPermission:)]) {
[session requestRecordPermission:^(BOOL granted) {
hasPermission = granted;
dispatch_semaphore_signal(self.waitAudioPermission);
}];
dispatch_semaphore_wait(self.waitAudioPermission, DISPATCH_TIME_FOREVER);
}
if (!hasPermission) {
NSLog(@"No permission for recorder.");
return ret;
}
if (!session.isInputAvailable) {
NSLog(@"Input device is not available");
return ret;
}
[session setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth
error:nil];
ret = YES;
NSLog(@"rec environment is OK");
return ret;
}
- (BOOL)initAudioComponent {
AudioComponentDescription audioDesc;
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
audioDesc.componentFlags = 0;
audioDesc.componentFlagsMask = 0;
AudioComponent inputComponent = AudioComponentFindNext(NULL, &audioDesc);
AudioComponentInstanceNew(inputComponent, &audioUnit);
return TRUE;
}
- (BOOL)initFormat {
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = REC_SAMPLE_RATE;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;
OSStatus status = noErr;
status = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
INPUT_BUS,
&audioFormat,
sizeof(audioFormat));
if (status != noErr) {
NSLog(@"initFormat SetOutput Error with status: %d", (int)status);
return FALSE;
}
return TRUE;
}
- (BOOL)initRecordCallback {
AURenderCallbackStruct recordCallback;
recordCallback.inputProc = RecordCallback;
recordCallback.inputProcRefCon = (__bridge void *)self;
OSStatus status = noErr;
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
INPUT_BUS,
&recordCallback,
sizeof(recordCallback));
if (status != noErr) {
NSLog(@"initRecordCallback SetRenderCallBack error with status: %d", (int)status);
return FALSE;
}
return TRUE;
}
- (BOOL)initAudioProperty {
UInt32 flag = 1;
OSStatus status = noErr;
status = AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
INPUT_BUS,
&flag,
sizeof(flag));
if (status != noErr) {
NSLog(@"initAudioProperty SetInputIO error with status: %d", (int)status);
return FALSE;
}
return TRUE;
}
@end
//
// VoiceAsr.h
// aivoice_plugin
//
// Created by benben on 2024/9/7.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface VoiceAsr : NSObject
@end
NS_ASSUME_NONNULL_END
//
// VoiceAsr.m
// aivoice_plugin
//
// Created by benben on 2024/9/7.
//
#import "VoiceAsr.h"
#import <SpeechEngineToB/SpeechEngine.h>
#import <AVFoundation/AVFoundation.h>
#import "SettingsHelper.h"
#import "StreamRecorder.h"
#import "SensitiveDefines.h"
@interface VoiceAsr ()<SpeechEngineDelegate>
@property (strong, nonatomic) SpeechEngine *curEngine;
// Debug Path: 用于存放一些 SDK 相关的文件,比如模型、日志等
@property (strong, nonatomic) NSString *debugPath;
@property (assign, nonatomic) BOOL engineStarted;
// Settings
@property (strong, nonatomic) Settings *settings;
// APP 层自定义的录音机,在音频来源为 Stream 时使用
@property (weak, nonatomic) StreamRecorder *streamRecorder;
// 一些用于统计的字段
@property (nonatomic, assign) long talkingFinisheTimestamp;
@end
@implementation VoiceAsr
#pragma mark - UI Actions
- (void)startEngineBtnClicked {
[self setResultText:@""];
NSLog(@"配置启动参数");
[self configStartAsrParams];
// Directive:启动引擎前调用SYNC_STOP指令,保证前一次请求结束。
NSLog(@"Directive: SEDirectiveSyncStopEngine");
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveSyncStopEngine];
if (ret != SENoError) {
NSLog(@"Send directive syncstop failed: %d", ret);
} else {
NSLog(@"启用引擎.");
NSLog(@"Directive: SEDirectiveStartEngine");
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveStartEngine];
if (ret == SERecCheckEnvironmentFailed) {
[self speechEngineNoPermission];
}
}
}
- (void)stopEngineBtnClicked {
NSLog(@"关闭引擎");
NSLog(@"Directive: SEDirectiveStopEngine");
[self.curEngine sendDirective:SEDirectiveStopEngine];
}
- (void)startEngineByLongPress:(bool)isBegin {
if (isBegin) {
[self setResultText:@""];
NSLog(@"配置启动参数");
[self configStartAsrParams];
//【可选配置】该按钮为长按模式,预期是按下开始录音,抬手结束录音,需要关闭云端自动判停功能。
[self.curEngine setBoolParam:FALSE forKey:SE_PARAMS_KEY_ASR_AUTO_STOP_BOOL];
// Directive:启动引擎前调用SYNC_STOP指令,保证前一次请求结束。
NSLog(@"Directive: SEDirectiveSyncStopEngine");
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveSyncStopEngine];
if (ret != SENoError) {
NSLog(@"Send directive syncstop failed: %d", ret);
} else {
// Directive:启动引擎指令。
NSLog(@"Directive: SEDirectiveStartEngine");
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveStartEngine];
if (ret == SERecCheckEnvironmentFailed) {
[self speechEngineNoPermission];
}
}
} else if (!isBegin) {
self.talkingFinisheTimestamp = [[NSDate date] timeIntervalSince1970] * 1000;
// Directive:结束音频输入。
NSLog(@"Directive: SEDirectiveFinishTalking");
[self.curEngine sendDirective:SEDirectiveFinishTalking];
if ([[self getRecorderType] isEqualToString:SE_RECORDER_TYPE_STREAM]) {
[self.streamRecorder stop];
}
}
}
#pragma mark - Config & Init & Uninit Methods
-(void)configInitParams{
//【必需配置】Engine Name
[self.curEngine setStringParam:SE_ASR_ENGINE forKey:SE_PARAMS_KEY_ENGINE_NAME_STRING];
//【可选配置】Debug & Log
[self.curEngine setStringParam:self.debugPath forKey:SE_PARAMS_KEY_DEBUG_PATH_STRING];
[self.curEngine setStringParam:SE_LOG_LEVEL_DEBUG forKey:SE_PARAMS_KEY_LOG_LEVEL_STRING];
//【可选配置】UID & deviceID: 用于定位线上问题
[self.curEngine setStringParam:SDEF_UID forKey:SE_PARAMS_KEY_UID_STRING];
// [self.curEngine setStringParam:self.deviceID forKey:SE_PARAMS_KEY_DEVICE_ID_STRING];
//【必需配置】配置音频来源
[self.curEngine setStringParam:[self getRecorderType] forKey:SE_PARAMS_KEY_RECORDER_TYPE_STRING];
if ([self.settings getBool:SETTING_ASR_RECORDER_SAVE]) {
//【可选配置】录音文件保存路径,如配置,SDK会将录音保存到该路径下,文件格式为 .wav
[self.curEngine setStringParam:self.debugPath forKey:SE_PARAMS_KEY_ASR_REC_PATH_STRING];
}
// 当音频来源为 RECORDER_TYPE_STREAM 时,如输入音频采样率不等于 16K,需添加如下配置
if ([[self getRecorderType] isEqualToString:SE_RECORDER_TYPE_STREAM]) {
if ([self.streamRecorder getSampleRate] != 16000 || [self.streamRecorder getChannel] != 1) {
// 当音频来源为 RECORDER_TYPE_STREAM 时【必需配置】,否则【无需配置】
// 启用 SDK 内部的重采样
[self.curEngine setBoolParam:TRUE forKey:SE_PARAMS_KEY_ENABLE_RESAMPLER_BOOL];
// 将重采样所需的输入采样率设置为 APP 层输入的音频的实际采样率
[self.curEngine setIntParam:[self.streamRecorder getSampleRate] forKey:SE_PARAMS_KEY_CUSTOM_SAMPLE_RATE_INT];
[self.curEngine setIntParam:[self.streamRecorder getChannel] forKey:SE_PARAMS_KEY_CUSTOM_CHANNEL_INT];
}
}
NSString *address = [self.settings getString:SETTING_ADDRESS];
if (!address.length) {
address = SDEF_DEFAULT_ADDRESS;
}
NSLog(@"Current address: %@", address);
//【必需配置】识别服务域名
[self.curEngine setStringParam:address forKey:SE_PARAMS_KEY_ASR_ADDRESS_STRING];
NSString *uri = [self.settings getString:SETTING_URI];
if (!uri.length) {
uri = SDEF_ASR_DEFAULT_URI;
}
NSLog(@"Current uri: %@", uri);
//【必需配置】识别服务Uri
[self.curEngine setStringParam:uri forKey:SE_PARAMS_KEY_ASR_URI_STRING];
NSString* appID = [self.settings getString:SETTING_APPID];
//【必需配置】鉴权相关:Appid
[self.curEngine setStringParam:appID.length <= 0 ? SDEF_APPID : appID forKey:SE_PARAMS_KEY_APP_ID_STRING];
//【必需配置】鉴权相关:Token
NSString* token = [self.settings getString:SETTING_TOKEN];
[self.curEngine setStringParam:token forKey:SE_PARAMS_KEY_APP_TOKEN_STRING];
NSString* cluster = [self.settings getString:SETTING_CLUSTER];
NSLog(@"Current cluster: %@", cluster);
//【必需配置】识别服务所用集群
[self.curEngine setStringParam:cluster.length <= 0 ? SDEF_ASR_DEFAULT_CLUSTER : cluster forKey:SE_PARAMS_KEY_ASR_CLUSTER_STRING];
//【可选配置】在线请求的建连与接收超时,一般不需配置使用默认值即可
[self.curEngine setIntParam:3000 forKey:SE_PARAMS_KEY_ASR_CONN_TIMEOUT_INT];
[self.curEngine setIntParam:5000 forKey:SE_PARAMS_KEY_ASR_RECV_TIMEOUT_INT];
//【可选配置】在线请求断连后,重连次数,默认值为0,如果需要开启需要设置大于0的次数
[self.curEngine setIntParam:[self.settings getInt:SETTING_ASR_MAX_RETRY_TIMES] forKey:SE_PARAMS_KEY_ASR_MAX_RETRY_TIMES_INT];
//【可选配置】音频采样率,默认16000
[self.curEngine setIntParam:[self.settings getInt:SETTING_SAMPLE_RATE] forKey:SE_PARAMS_KEY_SAMPLE_RATE_INT];
//【可选配置】音频通道数,默认1,可选1或2
[self.curEngine setIntParam:[self.settings getInt:SETTING_CHANNEL] forKey:SE_PARAMS_KEY_CHANNEL_NUM_INT];
//【可选配置】上传给服务的音频通道数,默认1,可选1或2,一般与SE_PARAMS_KEY_SAMPLE_RATE_INT保持一致即可
[self.curEngine setIntParam:[self.settings getInt:SETTING_CHANNEL] forKey:SE_PARAMS_KEY_UP_CHANNEL_NUM_INT];
}
-(void)configStartAsrParams{
//【可选配置】是否启用云端自动判停
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ASR_AUTO_STOP] forKey:SE_PARAMS_KEY_ASR_AUTO_STOP_BOOL];
//【可选配置】是否开启顺滑(DDC)
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ASR_ENABLE_DDC] forKey:SE_PARAMS_KEY_ASR_ENABLE_DDC_BOOL];
//【可选配置】是否开启文字转数字(ITN)
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ASR_ENABLE_ITN] forKey:SE_PARAMS_KEY_ASR_ENABLE_ITN_BOOL];
//【可选配置】是否开启标点
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ASR_ENABLE_NLU_PUNC] forKey:SE_PARAMS_KEY_ASR_SHOW_NLU_PUNC_BOOL];
//【可选配置】是否隐藏句尾标点
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ASR_DISABLE_END_PUNC] forKey:SE_PARAMS_KEY_ASR_DISABLE_END_PUNC_BOOL];
//【可选配置】设置识别语种
[self.curEngine setStringParam:[self.settings getString:SETTING_ASR_LANGUAGE] forKey:SE_PARAMS_KEY_ASR_LANGUAGE_STRING];
//【可选配置】控制识别结果返回的形式,全量返回或增量返回,默认为全量
[self.curEngine setStringParam:[self.settings getOptionsValue:SETTING_ASR_RESULT_TYPE] forKey:SE_PARAMS_KEY_ASR_RESULT_TYPE_STRING];
//【可选配置】设置VAD头部静音时长,用户多久没说话视为空音频,即静音检测时长
[self.curEngine setIntParam:[self.settings getInt:SETTING_ASR_VAD_START_SILENCE_TIME] forKey:SE_PARAMS_KEY_ASR_VAD_START_SILENCE_TIME_INT];
//【可选配置】设置VAD尾部静音时长,用户说话后停顿多久视为说话结束,即自动判停时长
[self.curEngine setIntParam:[self.settings getInt:SETTING_ASR_VAD_END_SILENCE_TIME] forKey:SE_PARAMS_KEY_ASR_VAD_END_SILENCE_TIME_INT];
//【可选配置】用户音频输入最大时长,仅一句话识别场景生效,单位毫秒,默认为 150000ms.
[self.curEngine setIntParam:[self.settings getInt:SETTING_VAD_MAX_SPEECH_DURATION] forKey:SE_PARAMS_KEY_VAD_MAX_SPEECH_DURATION_INT];
//【可选配置】控制是否返回录音音量,在 APP 需要显示音频波形时可以启用
[self.curEngine setBoolParam:[self.settings getBool:SETTING_GET_VOLUME] forKey:SE_PARAMS_KEY_ENABLE_GET_VOLUME_BOOL];
//【可选配置】更新 ASR 热词
if ([self.settings getString:SETTING_ASR_HOTWORDS].length != 0) {
[self setHotWords:[self.settings getString:SETTING_ASR_HOTWORDS]];
}
//【可选配置】设置纠错词表,识别结果会根据设置的纠错词纠正结果,例如:"{\"古爱玲\":\"谷爱凌\"}",当识别结果中出现"古爱玲"时会替换为"谷爱凌"
[self.curEngine setStringParam:[self.settings getString:SETTING_ASR_CORRECTWORDS] forKey:SE_PARAMS_KEY_ASR_CORRECT_WORDS_STRING];
NSString* recorderType = [self getRecorderType];
NSLog(@"录音模式: %@", recorderType);
if ([recorderType isEqualToString:SE_RECORDER_TYPE_STREAM]) {
if (![self.streamRecorder start]) {
[self speechEngineNoPermission];
}
} else if ([recorderType isEqualToString:SE_RECORDER_TYPE_FILE]) {
// 使用音频文件识别时,需要设置文件的绝对路径
NSString* file_path = [NSString stringWithFormat:@"%@/%@", self.debugPath, @"asr_rec_file.pcm"];
NSLog(@"输入的音频文件路径: %@", file_path);
// 使用音频文件识别时【必须配置】,否则【无需配置】
[self.curEngine setStringParam:file_path forKey:SE_PARAMS_KEY_RECORDER_FILE_STRING];
}
}
- (void)setHotWords:(NSString*) hotWords {
// 更新 ASR 热词,例如:"{\"hotwords\":[{\"word\":\"过秦论\",\"scale\":2.0}]}"
// scale为float类型参数,其中叠词的范围为[1.0,2.0],非叠词的范围为[1.0,50.0],scale值越大,结果中出现热词的概率越大
[self.curEngine sendDirective:SEDirectiveUpdateAsrHotWords data: hotWords];
}
- (void)initEngine {
NSLog(@"获取设备ID,调试使用");
// AppDelegate *appDelegate = [ViewController getAppDelegate];
// if (appDelegate == nil) {
// appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// }
// [ViewController setAppDelegate:appDelegate];
// self.deviceID = appDelegate.deviceID;
// NSLog(@"获取设备ID成功: %@", self.deviceID);
NSLog(@"创建引擎");
if (self.curEngine == nil) {
self.curEngine = [[SpeechEngine alloc] init];
if (![self.curEngine createEngineWithDelegate:self]) {
NSLog(@"引擎创建失败.");
return;
}
}
// [self.resultTextView setTextColor:UIColor.blackColor];
NSLog(@"SDK 版本号: %@", [self.curEngine getVersion]);
self.debugPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"当前调试路径: %@", self.debugPath);
NSLog(@"配置初始化参数");
[self configInitParams];
NSLog(@"引擎初始化");
SEEngineErrorCode ret = [self.curEngine initEngine];
if (ret == SENoError) {
NSLog(@"初始化成功");
[self speechEngineInitSucceeded];
} else {
NSLog(@"初始化失败,返回值: %d", ret);
[self speechEngineInitFailed:ret];
}
}
- (void)uninitEngine {
if (self.curEngine != nil) {
NSLog(@"引擎析构");
[self.curEngine destroyEngine];
self.curEngine = nil;
NSLog(@"引擎析构完成");
}
}
- (void)speechEngineInitSucceeded {
[self.streamRecorder setSpeechEngine:self.curEngine];
// dispatch_async(dispatch_get_main_queue(), ^{
// /* [self.st*/atusTextView setText:@"Ready"];
// [self setResultText:[NSString stringWithFormat:@"DeviceID: %@", self.deviceID]];
// self.uninitialEngineButton.enabled = TRUE;
// self.initialEngineButton.enabled = FALSE;
// self.startEngineButton.enabled = TRUE;
// self.recordButton.enabled = TRUE;
// });
}
- (void)speechEngineInitFailed:(int)initStatus {
dispatch_async(dispatch_get_main_queue(), ^{
[self uninitEngine];
// [self.statusTextView setText:[[NSString alloc] initWithFormat:@"Failed to init engine, %d!", initStatus]];
// self.initialEngineButton.enabled = TRUE;
// self.uninitialEngineButton.enabled = FALSE;
});
}
- (void)speechEngineNoPermission {
dispatch_async(dispatch_get_main_queue(), ^{
[self uninitEngine];
// [self.statusTextView setText:@"No permission!"];
// self.initialEngineButton.enabled = TRUE;
// self.uninitialEngineButton.enabled = FALSE;
});
}
#pragma mark - Message Callback
- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
NSLog(@"Message Type: %d.", type);
switch (type) {
case SEEngineStart:
// Callback: 引擎启动成功回调
NSLog(@"Callback: 引擎启动成功");
[self speechEngineStarted];
break;
case SEEngineStop:
// Callback: 引擎关闭回调
NSLog(@"Callback: 引擎关闭");
[self speechEngineStopped];
break;
case SEEngineError:
// Callback: 错误信息回调
NSLog(@"Callback: 错误信息: %@", data);
[self speechEngineError:data];
break;
case SEConnectionConnected:
NSLog(@"Callback: 建连成功");
break;
case SEAsrPartialResult:
// Callback: ASR 当前请求的部分结果回调
NSLog(@"Callback: ASR 当前请求的部分结果");
[self speechEngineResult:data isFinal:FALSE];
break;
case SEFinalResult:
// Callback: ASR 当前请求最终结果回调
NSLog(@"Callback: ASR 当前请求最终结果");
[self speechEngineResult:data isFinal:TRUE];
break;
case SEVolumeLevel:
// Callback: 录音音量回调
NSLog(@"Callback: 录音音量");
break;
default:
break;
}
}
- (void)speechEngineStarted {
dispatch_async(dispatch_get_main_queue(), ^{
self.engineStarted = true;
// [self.statusTextView setText:@"Engine Started!"];
// self.startEngineButton.enabled = FALSE;
// self.stopEngineButton.enabled = TRUE;
// self.recordButton.enabled = FALSE;
});
}
- (void)speechEngineStopped {
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self getRecorderType] isEqualToString:SE_RECORDER_TYPE_STREAM]) {
[self.streamRecorder stop];
}
self.engineStarted = FALSE;
// [self.statusTextView setText:@"Engine Stopped!"];
// self.startEngineButton.enabled = TRUE;
// self.stopEngineButton.enabled = FALSE;
// self.recordButton.enabled = TRUE;
});
}
- (void)speechEngineResult:(NSData *)data isFinal:(BOOL)isFinal {
dispatch_async(dispatch_get_main_queue(), ^{
// 计算由录音结束到 ASR 最终结果之间的延迟
long response_delay = 0;
if (isFinal && self.talkingFinisheTimestamp > 0) {
response_delay = [self timeDelayFrom:self.talkingFinisheTimestamp];
self.talkingFinisheTimestamp = 0;
}
// 从回调的 json 数据中解析 ASR 结果
NSError *error;
NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
if (![jsonResult objectForKey:@"result"]) {
return;
}
// 在 UI 显示 ASR 结果和延迟信息
NSString *result = [[[jsonResult objectForKey:@"result"] firstObject] objectForKey:@"text"];
if (result.length == 0) {
return;
}
NSMutableString *text = [[NSMutableString alloc] initWithString:@""];
[text appendFormat:@"result: %@", result];
if (isFinal) {
[text appendFormat:@"\nreqid: %@", [jsonResult objectForKey:@"reqid"]];
[text appendFormat:@"\nresponse_delay: %ld", response_delay];
}
[self setResultText:[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
});
}
- (void)speechEngineError:(NSData *)data {
dispatch_async(dispatch_get_main_queue(), ^{
// 从回调的 json 数据中解析错误码和错误详细信息
id error_json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if ([error_json isKindOfClass:[NSDictionary class]]) {
NSDictionary *error_info = error_json;
// 在 UI 显示错误信息
if ([error_info objectForKey:@"name"] != nil) {
NSString* error_msg = [[error_json objectForKey:@"err_msg"] stringValue];
NSString* reqid = [[error_json objectForKey:@"reqid"] stringValue];
[self setResultText:[NSString stringWithFormat:@"reqid: %@, error: %@", reqid, error_msg]];
} else {
[self setResultText:[NSString stringWithFormat:@"%@", error_info]];
}
}
});
}
#pragma mark - Helper
- (NSString *)getRecorderType {
SettingOptions* recorderTypeOptions = [self.settings getOptions:SETTING_RECORD_TYPE];
switch (recorderTypeOptions.chooseIdx) {
case 0:
return SE_RECORDER_TYPE_RECORDER;
case 1:
return SE_RECORDER_TYPE_FILE;
case 2:
return SE_RECORDER_TYPE_STREAM;
default:
break;
}
return @"";
}
- (void)setResultText:(NSString *)result {
// dispatch_async(dispatch_get_main_queue(), ^{
// [self.resultTextView setText:[result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
// });
}
- (long)timeDelayFrom:(long)pastTimestamp {
return [[NSDate date] timeIntervalSince1970] * 1000 - pastTimestamp;
}
@end
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint aivoice_plugin.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'aivoice_plugin'
s.version = '0.0.1'
s.summary = 'A new Flutter plugin project.'
s.description = <<-DESC
A new Flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.dependency 'SpeechEngineToB'
s.platform = :ios, '11.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
end
import 'aivoice_plugin_platform_interface.dart';
class AivoicePlugin {
Future<String?> getPlatformVersion() {
return AivoicePluginPlatform.instance.getPlatformVersion();
}
// 新增的 initEngine 方法
Future<void> initEngine(Map<String, dynamic> config) {
return AivoicePluginPlatform.instance.initEngine(config);
}
}
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'aivoice_plugin_platform_interface.dart';
/// An implementation of [AivoicePluginPlatform] that uses method channels.
class MethodChannelAivoicePlugin extends AivoicePluginPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('aivoice_plugin');
@override
Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
}
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'aivoice_plugin_method_channel.dart';
abstract class AivoicePluginPlatform extends PlatformInterface {
/// Constructs a AivoicePluginPlatform.
AivoicePluginPlatform() : super(token: _token);
static final Object _token = Object();
static AivoicePluginPlatform _instance = MethodChannelAivoicePlugin();
/// The default instance of [AivoicePluginPlatform] to use.
///
/// Defaults to [MethodChannelAivoicePlugin].
static AivoicePluginPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [AivoicePluginPlatform] when
/// they register themselves.
static set instance(AivoicePluginPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion();
// 新增的 initEngine 方法
Future<void> initEngine(Map<String, dynamic> config);
}
import 'package:flutter/services.dart';
import 'aivoice_plugin_platform_interface.dart';
class MethodChannelAivoicePlugin extends AivoicePluginPlatform {
final MethodChannel _channel = const MethodChannel('aivoice_plugin');
@override
Future<String?> getPlatformVersion() {
return _channel.invokeMethod<String>('getPlatformVersion');
}
@override
Future<void> initEngine(Map<String, dynamic> config) {
return _channel.invokeMethod<void>('initEngine', config);
}
}
name: aivoice_plugin
description: "A new Flutter plugin project."
version: 0.0.1
homepage:
environment:
sdk: '>=3.3.4 <4.0.0'
flutter: '>=3.3.0'
dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# This section identifies this Flutter project as a plugin project.
# The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
# which should be registered in the plugin registry. This is required for
# using method channels.
# The Android 'package' specifies package in which the registered class is.
# This is required for using method channels on Android.
# The 'ffiPlugin' specifies that native code should be built and bundled.
# This is required for using `dart:ffi`.
# All these are used by the tooling to maintain consistency when
# adding or updating assets for this project.
plugin:
platforms:
android:
package: com.example.aivoice_plugin
pluginClass: AivoicePlugin
ios:
pluginClass: AivoicePlugin
# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:aivoice_plugin/aivoice_plugin_method_channel.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
MethodChannelAivoicePlugin platform = MethodChannelAivoicePlugin();
const MethodChannel channel = MethodChannel('aivoice_plugin');
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
(MethodCall methodCall) async {
return '42';
},
);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
});
test('getPlatformVersion', () async {
expect(await platform.getPlatformVersion(), '42');
});
}
import 'package:flutter_test/flutter_test.dart';
import 'package:aivoice_plugin/aivoice_plugin.dart';
import 'package:aivoice_plugin/aivoice_plugin_platform_interface.dart';
import 'package:aivoice_plugin/aivoice_plugin_method_channel.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockAivoicePluginPlatform
with MockPlatformInterfaceMixin
implements AivoicePluginPlatform {
@override
Future<String?> getPlatformVersion() => Future.value('42');
}
void main() {
final AivoicePluginPlatform initialPlatform = AivoicePluginPlatform.instance;
test('$MethodChannelAivoicePlugin is the default instance', () {
expect(initialPlatform, isInstanceOf<MethodChannelAivoicePlugin>());
});
test('getPlatformVersion', () async {
AivoicePlugin aivoicePlugin = AivoicePlugin();
MockAivoicePluginPlatform fakePlatform = MockAivoicePluginPlatform();
AivoicePluginPlatform.instance = fakePlatform;
expect(await aivoicePlugin.getPlatformVersion(), '42');
});
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论