├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── datawedge_flutter ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── darryncampbell │ │ │ │ │ └── datawedgeflutter │ │ │ │ │ ├── DWInterface.kt │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── Scan.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart └── screenshots ├── app.jpg ├── dw-profile-1.jpg ├── dw-profile-2.jpg ├── dw-profile-3.jpg ├── dw-profiles.jpg └── google-flutter-logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Dart", 9 | "program": "bin/main.dart", 10 | "request": "launch", 11 | "type": "dart" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Darryn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *Please be aware that this application / sample is provided as-is for demonstration purposes without any guarantee of support* 2 | ========================================================= 3 | 4 | # DataWedge Flutter Demo 5 | 6 | Over the past couple of years I have seen an increasing interest in developing Flutter apps for Zebra Android mobile devices. Until recently I had directed developers to a 3rd party flutter demo that shows how to wrap the EMDK (Zebra's Android scanner SDK). That sample is at https://github.com/acaliaro/flutterZebraEmdk but Zebra's recommended approach is to use DataWedge rather than the EMDK for scanner integration and I noticed a number of people asking about non-Zebra device compatibility, something that is more difficult to achieve with the EMDK. 7 | 8 | **This demo application shows how to interface to Zebra's DataWedge service from a Flutter application** 9 | 10 | For expediency, this article assumes familiarity with Zebra's DataWedge tool as well as the DataWedge profile mechanism. For an overview of DataWedge, please refer to the [DataWedge Techdocs page](https://techdocs.zebra.com/datawedge/latest/guide/overview/). This project will use DataWedge to capture data aswell as the DataWedge API to configure a profile and control the scanner with a button on the UI. This project does *not* demonstrate the full capabilities of DataWedge through Flutter, see 'not covered by this sample', below. 11 | 12 | ## Prerequisites 13 | 14 | You need to have [Flutter installed](https://flutter.dev/docs/get-started/install) in order to run this sample. The process is fairly straight forward and there are abundant resources out there to help you get Flutter configured on your system 15 | 16 | ``` 17 | Install flutter 18 | >flutter run 19 | Optionally: Configure the Flutter SDK in Android Studio and run your application from there 20 | ``` 21 | 22 | ## Sample Application 23 | 24 | This sample application draws heavily on the official Flutter sample for "[platform_channel](https://github.com/flutter/flutter/blob/master/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java)" as well as the approach followed by the previously mentioned 3rd party [Flutter EMDK sample](https://github.com/acaliaro/flutterZebraEmdk). Because the native code is written in Kotlin I also re-used a lot of the code I previously wrote for my [DataWedge Kotlin sample](https://github.com/darryncampbell/DataWedgeKotlin). 25 | 26 | The sample works as follows: 27 | - A [MethodChannel](https://api.flutter.dev/flutter/services/MethodChannel-class.html) is used to invoke the [DataWedge API](https://techdocs.zebra.com/datawedge/latest/guide/api/) to instruct DataWedge to do things, e.g. [SOFT_SCAN_TRIGGER](https://techdocs.zebra.com/datawedge/latest/guide/api/softscantrigger/). Only a couple of methods are used by this demo app but there are about 30 APIs available in DataWedge. 28 | - An [EventChannel](https://api.flutter.dev/flutter/services/EventChannel-class.html) is used to receive data back from DataWedge. This demo only receives *scans* but this channel could also be used to parse return values from the asynchronous DataWedge APIs, e.g. [GET_VERSION](https://techdocs.zebra.com/datawedge/latest/guide/api/getversioninfo/). 29 | 30 | ![Sample application](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/app.jpg) 31 | 32 | As can be seen from the picture, the last scanned barcode is displayed and a scan can be initiated with the blue SCAN button. *I personally found it challenging to define my UI in Flutter - respect to those developers who find this easy* 33 | 34 | ## User Interface (Dart) code to receive data (e.g. scans) from DataWedge 35 | 36 | Scanned data will be received from the native (Kotlin) layer over an EventChannel as a stringified JSON object. This seemed the easiest way to pass an object over the EventChannel rather than try to get Dart to understand my Kotlin class. Set up the EventChannel and declare an onEvent listener to update the UI when a barcode is scanned. 37 | 38 | ```dart 39 | static const EventChannel scanChannel = 40 | EventChannel('com.darryncampbell.datawedgeflutter/scan'); 41 | 42 | @override 43 | void initState() { 44 | super.initState(); 45 | scanChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); 46 | } 47 | 48 | void _onEvent(Object event) { 49 | setState(() { 50 | Map barcodeScan = jsonDecode(event); 51 | _barcodeString = "Barcode: " + barcodeScan['scanData']; 52 | _barcodeSymbology = "Symbology: " + barcodeScan['symbology']; 53 | _scanTime = "At: " + barcodeScan['dateTime']; 54 | }); 55 | } 56 | ``` 57 | 58 | ## Native (Kotlin) code to handle scans received from DataWedge 59 | 60 | Scan data is received from DataWedge as a Broadcast Intent. A DataWedge profile (created automatically - see later) is required to configure DataWedge to send this broadcast intent. The native code will create the broadcast receiver and when a broadcast is received from a scan, it is sent to the UI (Dart) code over the EventChannel. 61 | 62 | ```kotlin 63 | private val PROFILE_INTENT_ACTION = "com.darryncampbell.datawedgeflutter.SCAN" 64 | private val SCAN_CHANNEL = "com.darryncampbell.datawedgeflutter/scan" 65 | 66 | EventChannel(flutterEngine.dartExecutor, SCAN_CHANNEL).setStreamHandler( 67 | object : StreamHandler { 68 | private var dataWedgeBroadcastReceiver: BroadcastReceiver? = null 69 | override fun onListen(arguments: Any?, events: EventSink?) { 70 | dataWedgeBroadcastReceiver = createDataWedgeBroadcastReceiver(events) 71 | val intentFilter = IntentFilter() 72 | intentFilter.addAction(PROFILE_INTENT_ACTION) 73 | registerReceiver( 74 | dataWedgeBroadcastReceiver, intentFilter) 75 | } 76 | 77 | override fun onCancel(arguments: Any?) { 78 | unregisterReceiver(dataWedgeBroadcastReceiver) 79 | dataWedgeBroadcastReceiver = null 80 | } 81 | } 82 | ) 83 | ``` 84 | 85 | Received barcodes are parsed from the Intent into a 'Scan' object. The stringified JSON representation of this Scan is sent over the EventChannel. 86 | 87 | ```kotlin 88 | private fun createDataWedgeBroadcastReceiver(events: EventSink?): BroadcastReceiver? { 89 | return object : BroadcastReceiver() { 90 | override fun onReceive(context: Context, intent: Intent) { 91 | if (intent.action.equals(PROFILE_INTENT_ACTION)) 92 | { 93 | // A barcode has been scanned 94 | var scanData = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_DATA_STRING) 95 | var symbology = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_LABEL_TYPE) 96 | var date = Calendar.getInstance().getTime() 97 | var df = SimpleDateFormat("dd/MM/yyyy HH:mm:ss") 98 | var dateTimeString = df.format(date) 99 | var currentScan = Scan(scanData, symbology, dateTimeString); 100 | events?.success(currentScan.toJson()) 101 | } 102 | // Could handle return values from DW here such as RETURN_GET_ACTIVE_PROFILE 103 | // or RETURN_ENUMERATE_SCANNERS 104 | } 105 | } 106 | } 107 | ``` 108 | 109 | ## User Interface (Dart) code to send commands to DataWedge 110 | 111 | The MethodChannel is used to send instructions to DataWedge. The [DataWedge API](https://techdocs.zebra.com/datawedge/latest/guide/api/) contains APIs which take a range of parameters, from simple Strings to complex nested Bundle structures. There may have been a better way to do this but invokeMethod can only take a single argument type so to exchange two strings I converted them to a stringified JSON object. 112 | 113 | The demo code also handles profile creation (not shown below) which is done entirely in the native code rather than try to exchange the nested bundle structure between Dart and Kotlin. 114 | 115 | ```dart 116 | static const MethodChannel methodChannel = 117 | MethodChannel('com.darryncampbell.datawedgeflutter/command'); 118 | 119 | Future _sendDataWedgeCommand(String command, String parameter) async { 120 | try { 121 | String argumentAsJson = "{\"command\":$command,\"parameter\":$parameter}"; 122 | await methodChannel.invokeMethod( 123 | 'sendDataWedgeCommandStringParameter', argumentAsJson); 124 | } on PlatformException { 125 | // Error invoking Android method 126 | } 127 | } 128 | ``` 129 | 130 | Handler for the onTouchDown event, initiate the scan when the button is pressed. Calls the above function with the appropriate DataWedge API command and parameter. 131 | 132 | ```dart 133 | void startScan() { 134 | setState(() { 135 | _sendDataWedgeCommand( 136 | "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "START_SCANNING"); 137 | }); 138 | } 139 | ``` 140 | 141 | ## Native (Kotlin) code to send commands to DataWedge 142 | 143 | Parse the commands and determine which DataWedge API to call. All DataWedge APIs are invoked by sending a Broadcast Intent to a pre-defined Action which the DataWedge service is always listening for. 144 | 145 | ```kotlin 146 | MethodChannel(flutterEngine.dartExecutor, COMMAND_CHANNEL).setMethodCallHandler { call, result -> 147 | if (call.method == "sendDataWedgeCommandStringParameter") 148 | { 149 | val arguments = JSONObject(call.arguments.toString()) 150 | val command: String = arguments.get("command") as String 151 | val parameter: String = arguments.get("parameter") as String 152 | sendCommandString(applicationContext, command, parameter) 153 | } 154 | else { 155 | result.notImplemented() 156 | } 157 | } 158 | 159 | fun sendCommandString(context: Context, command: String, parameter: String) { 160 | val dwIntent = Intent() 161 | dwIntent.action = "com.symbol.datawedge.api.ACTION" 162 | dwIntent.putExtra(command, parameter) 163 | context.sendBroadcast(dwIntent) 164 | } 165 | ``` 166 | ### DataWedge Configuration 167 | 168 | As previously mentioned, although the Flutter application is listening for broadcast Intents, DataWedge needs to be configured to send the appropriate Intent whenever a barcode is scanned. **The sample app will do this automatically** with a combination of the [CREATE_PROFILE](https://techdocs.zebra.com/datawedge/latest/guide/api/createprofile/) and [SET_CONFIG APIs](https://techdocs.zebra.com/datawedge/latest/guide/api/setconfig/) provided your version of DataWedge is 6.4 or higher. 169 | 170 | If for whatever reason the profile is not automatically created you can do so manually by launching DataWedge on the device and matching the screenshots below to define the DataWedgeFlutterDemo profile. 171 | 172 | ![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profiles.jpg) 173 | ![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-1.jpg) 174 | ![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-2.jpg) 175 | ![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-3.jpg) 176 | 177 | ## Not covered by this sample 178 | 179 | This is a very basic sample designed to only show the basics of capturing data in a Flutter app on a Zebra Android device. 180 | 181 | Many of the DataWedge APIs return values back to the application, for example [GET_VERSION](https://techdocs.zebra.com/datawedge/latest/guide/api/getversioninfo/) but none of those APIs are shown in this demo. You can reuse the existing EventChannel for this purpose. 182 | 183 | Many of the DataWedge APIs take complex data types like [SET_CONFIG APIs](https://techdocs.zebra.com/datawedge/latest/guide/api/setconfig/). Ideally you could define these complex structures in Dart and send them over the MethodChannel... this may well be possible (This Medium article on [Flutter Platform Channels](https://medium.com/flutter/flutter-platform-channels-ce7f540a104e) talks about BinaryMessages) but it is much simpler to define these in Kotlin, especially since [other apps already exist](https://github.com/darryncampbell/DataWedgeKotlin) which show how to call the APIs from Kotlin. 184 | 185 | ## Contributing 186 | This project welcomes contributions. Pleae check out the [Contributing guide](https://github.com/ZebraDevs/About/blob/master/CONTRIBUTING.md) to learn more on how to get started. 187 | 188 | ## License 189 | This project is released under the [MIT](LICENSE) license 190 | -------------------------------------------------------------------------------- /datawedge_flutter/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Exceptions to above rules. 43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 44 | -------------------------------------------------------------------------------- /datawedge_flutter/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 2294d75bfa8d067ba90230c0fc2268f3636d7584 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /datawedge_flutter/README.md: -------------------------------------------------------------------------------- 1 | # datawedgeflutter 2 | 3 | Accessing DataWedge from a Flutter app 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /datawedge_flutter/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | applicationId "com.darryncampbell.datawedgeflutter" 41 | minSdkVersion 16 42 | targetSdkVersion 28 43 | versionCode flutterVersionCode.toInteger() 44 | versionName flutterVersionName 45 | } 46 | 47 | buildTypes { 48 | release { 49 | // TODO: Add your own signing config for the release build. 50 | // Signing with the debug keys for now, so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | } 55 | 56 | flutter { 57 | source '../..' 58 | } 59 | 60 | dependencies { 61 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 62 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 63 | } 64 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/kotlin/com/darryncampbell/datawedgeflutter/DWInterface.kt: -------------------------------------------------------------------------------- 1 | package com.darryncampbell.datawedgeflutter 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | 7 | class DWInterface() { 8 | companion object { 9 | const val DATAWEDGE_SEND_ACTION = "com.symbol.datawedge.api.ACTION" 10 | const val DATAWEDGE_RETURN_ACTION = "com.symbol.datawedge.api.RESULT_ACTION" 11 | const val DATAWEDGE_RETURN_CATEGORY = "android.intent.category.DEFAULT" 12 | const val DATAWEDGE_EXTRA_SEND_RESULT = "SEND_RESULT" 13 | const val DATAWEDGE_SCAN_EXTRA_DATA_STRING = "com.symbol.datawedge.data_string" 14 | const val DATAWEDGE_SCAN_EXTRA_LABEL_TYPE = "com.symbol.datawedge.label_type" 15 | const val DATAWEDGE_SEND_CREATE_PROFILE = "com.symbol.datawedge.api.CREATE_PROFILE" 16 | const val DATAWEDGE_SEND_SET_CONFIG = "com.symbol.datawedge.api.SET_CONFIG" 17 | } 18 | 19 | fun sendCommandString(context: Context, command: String, parameter: String, sendResult: Boolean = false) { 20 | val dwIntent = Intent() 21 | dwIntent.action = DATAWEDGE_SEND_ACTION 22 | dwIntent.putExtra(command, parameter) 23 | if (sendResult) 24 | dwIntent.putExtra(DATAWEDGE_EXTRA_SEND_RESULT, "true") 25 | context.sendBroadcast(dwIntent) 26 | } 27 | 28 | fun sendCommandBundle(context: Context, command: String, parameter: Bundle) { 29 | val dwIntent = Intent() 30 | dwIntent.action = DATAWEDGE_SEND_ACTION 31 | dwIntent.putExtra(command, parameter) 32 | context.sendBroadcast(dwIntent) 33 | } 34 | } -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/kotlin/com/darryncampbell/datawedgeflutter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.darryncampbell.datawedgeflutter 2 | 3 | import android.content.* 4 | import android.os.Bundle 5 | import io.flutter.embedding.android.FlutterActivity 6 | import io.flutter.embedding.engine.FlutterEngine 7 | import io.flutter.plugin.common.EventChannel 8 | import io.flutter.plugin.common.EventChannel.EventSink 9 | import io.flutter.plugin.common.EventChannel.StreamHandler 10 | import io.flutter.plugin.common.MethodChannel 11 | import org.json.JSONObject 12 | import java.text.SimpleDateFormat 13 | import java.util.* 14 | import io.flutter.plugins.GeneratedPluginRegistrant; 15 | 16 | // This sample implementation is heavily based on the flutter demo at 17 | // https://github.com/flutter/flutter/blob/master/examples/platform_channel/android/app/src/main/java/com/example/platformchannel/MainActivity.java 18 | 19 | class MainActivity: FlutterActivity() { 20 | private val COMMAND_CHANNEL = "com.darryncampbell.datawedgeflutter/command" 21 | private val SCAN_CHANNEL = "com.darryncampbell.datawedgeflutter/scan" 22 | private val PROFILE_INTENT_ACTION = "com.darryncampbell.datawedgeflutter.SCAN" 23 | private val PROFILE_INTENT_BROADCAST = "2" 24 | 25 | private val dwInterface = DWInterface() 26 | 27 | override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 28 | GeneratedPluginRegistrant.registerWith(flutterEngine) 29 | EventChannel(flutterEngine.dartExecutor, SCAN_CHANNEL).setStreamHandler( 30 | object : StreamHandler { 31 | private var dataWedgeBroadcastReceiver: BroadcastReceiver? = null 32 | override fun onListen(arguments: Any?, events: EventSink?) { 33 | dataWedgeBroadcastReceiver = createDataWedgeBroadcastReceiver(events) 34 | val intentFilter = IntentFilter() 35 | intentFilter.addAction(PROFILE_INTENT_ACTION) 36 | intentFilter.addAction(DWInterface.DATAWEDGE_RETURN_ACTION) 37 | intentFilter.addCategory(DWInterface.DATAWEDGE_RETURN_CATEGORY) 38 | registerReceiver( 39 | dataWedgeBroadcastReceiver, intentFilter) 40 | } 41 | 42 | override fun onCancel(arguments: Any?) { 43 | unregisterReceiver(dataWedgeBroadcastReceiver) 44 | dataWedgeBroadcastReceiver = null 45 | } 46 | } 47 | ) 48 | 49 | MethodChannel(flutterEngine.dartExecutor, COMMAND_CHANNEL).setMethodCallHandler { call, result -> 50 | if (call.method == "sendDataWedgeCommandStringParameter") 51 | { 52 | val arguments = JSONObject(call.arguments.toString()) 53 | val command: String = arguments.get("command") as String 54 | val parameter: String = arguments.get("parameter") as String 55 | dwInterface.sendCommandString(applicationContext, command, parameter) 56 | // result.success(0); // DataWedge does not return responses 57 | } 58 | else if (call.method == "createDataWedgeProfile") 59 | { 60 | createDataWedgeProfile(call.arguments.toString()) 61 | } 62 | else { 63 | result.notImplemented() 64 | } 65 | } 66 | } 67 | 68 | private fun createDataWedgeBroadcastReceiver(events: EventSink?): BroadcastReceiver? { 69 | return object : BroadcastReceiver() { 70 | override fun onReceive(context: Context, intent: Intent) { 71 | if (intent.action.equals(PROFILE_INTENT_ACTION)) 72 | { 73 | // A barcode has been scanned 74 | var scanData = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_DATA_STRING) 75 | var symbology = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_LABEL_TYPE) 76 | var date = Calendar.getInstance().getTime() 77 | var df = SimpleDateFormat("dd/MM/yyyy HH:mm:ss") 78 | var dateTimeString = df.format(date) 79 | var currentScan = Scan(scanData, symbology, dateTimeString); 80 | events?.success(currentScan.toJson()) 81 | } 82 | // Could handle return values from DW here such as RETURN_GET_ACTIVE_PROFILE 83 | // or RETURN_ENUMERATE_SCANNERS 84 | } 85 | } 86 | } 87 | 88 | private fun createDataWedgeProfile(profileName: String) { 89 | // Create and configure the DataWedge profile associated with this application 90 | // For readability's sake, I have not defined each of the keys in the DWInterface file 91 | dwInterface.sendCommandString(this, DWInterface.DATAWEDGE_SEND_CREATE_PROFILE, profileName) 92 | val profileConfig = Bundle() 93 | profileConfig.putString("PROFILE_NAME", profileName) 94 | profileConfig.putString("PROFILE_ENABLED", "true") // These are all strings 95 | profileConfig.putString("CONFIG_MODE", "UPDATE") 96 | val barcodeConfig = Bundle() 97 | barcodeConfig.putString("PLUGIN_NAME", "BARCODE") 98 | barcodeConfig.putString("RESET_CONFIG", "true") // This is the default but never hurts to specify 99 | val barcodeProps = Bundle() 100 | barcodeConfig.putBundle("PARAM_LIST", barcodeProps) 101 | profileConfig.putBundle("PLUGIN_CONFIG", barcodeConfig) 102 | val appConfig = Bundle() 103 | appConfig.putString("PACKAGE_NAME", packageName) // Associate the profile with this app 104 | appConfig.putStringArray("ACTIVITY_LIST", arrayOf("*")) 105 | profileConfig.putParcelableArray("APP_LIST", arrayOf(appConfig)) 106 | dwInterface.sendCommandBundle(this, DWInterface.DATAWEDGE_SEND_SET_CONFIG, profileConfig) 107 | // You can only configure one plugin at a time in some versions of DW, now do the intent output 108 | profileConfig.remove("PLUGIN_CONFIG") 109 | val intentConfig = Bundle() 110 | intentConfig.putString("PLUGIN_NAME", "INTENT") 111 | intentConfig.putString("RESET_CONFIG", "true") 112 | val intentProps = Bundle() 113 | intentProps.putString("intent_output_enabled", "true") 114 | intentProps.putString("intent_action", PROFILE_INTENT_ACTION) 115 | intentProps.putString("intent_delivery", PROFILE_INTENT_BROADCAST) // "2" 116 | intentConfig.putBundle("PARAM_LIST", intentProps) 117 | profileConfig.putBundle("PLUGIN_CONFIG", intentConfig) 118 | dwInterface.sendCommandBundle(this, DWInterface.DATAWEDGE_SEND_SET_CONFIG, profileConfig) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/kotlin/com/darryncampbell/datawedgeflutter/Scan.kt: -------------------------------------------------------------------------------- 1 | package com.darryncampbell.datawedgeflutter 2 | 3 | import org.json.JSONObject; 4 | 5 | class Scan(val data: String, val symbology: String, val dateTime: String) 6 | { 7 | fun toJson(): String{ 8 | return JSONObject(mapOf( 9 | "scanData" to this.data, 10 | "symbology" to this.symbology, 11 | "dateTime" to this.dateTime 12 | )).toString(); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/datawedge_flutter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/datawedge_flutter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/datawedge_flutter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/datawedge_flutter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/datawedge_flutter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /datawedge_flutter/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /datawedge_flutter/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /datawedge_flutter/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /datawedge_flutter/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /datawedge_flutter/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /datawedge_flutter/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | 6 | void main() { 7 | runApp(MyApp()); 8 | } 9 | 10 | class MyApp extends StatelessWidget { 11 | // This widget is the root of your application. 12 | @override 13 | Widget build(BuildContext context) { 14 | return MaterialApp( 15 | title: 'DataWedge Flutter', 16 | theme: ThemeData( 17 | primarySwatch: Colors.orange, 18 | ), 19 | home: MyHomePage(title: 'DataWedge Flutter'), 20 | ); 21 | } 22 | } 23 | 24 | class MyHomePage extends StatefulWidget { 25 | MyHomePage({Key? key, required this.title}) : super(key: key); 26 | 27 | final String title; 28 | 29 | @override 30 | _MyHomePageState createState() => _MyHomePageState(); 31 | } 32 | 33 | class _MyHomePageState extends State { 34 | static const MethodChannel methodChannel = 35 | MethodChannel('com.darryncampbell.datawedgeflutter/command'); 36 | static const EventChannel scanChannel = 37 | EventChannel('com.darryncampbell.datawedgeflutter/scan'); 38 | 39 | // This example implementation is based on the sample implementation at 40 | // https://github.com/flutter/flutter/blob/master/examples/platform_channel/lib/main.dart 41 | // That sample implementation also includes how to return data from the method 42 | Future _sendDataWedgeCommand(String command, String parameter) async { 43 | try { 44 | String argumentAsJson = 45 | jsonEncode({"command": command, "parameter": parameter}); 46 | 47 | await methodChannel.invokeMethod( 48 | 'sendDataWedgeCommandStringParameter', argumentAsJson); 49 | } on PlatformException { 50 | // Error invoking Android method 51 | } 52 | } 53 | 54 | Future _createProfile(String profileName) async { 55 | try { 56 | await methodChannel.invokeMethod('createDataWedgeProfile', profileName); 57 | } on PlatformException { 58 | // Error invoking Android method 59 | } 60 | } 61 | 62 | String _barcodeString = "Barcode will be shown here"; 63 | String _barcodeSymbology = "Symbology will be shown here"; 64 | String _scanTime = "Scan Time will be shown here"; 65 | 66 | @override 67 | void initState() { 68 | super.initState(); 69 | scanChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); 70 | _createProfile("DataWedgeFlutterDemo"); 71 | } 72 | 73 | void _onEvent(event) { 74 | setState(() { 75 | Map barcodeScan = jsonDecode(event); 76 | _barcodeString = "Barcode: " + barcodeScan['scanData']; 77 | _barcodeSymbology = "Symbology: " + barcodeScan['symbology']; 78 | _scanTime = "At: " + barcodeScan['dateTime']; 79 | }); 80 | } 81 | 82 | void _onError(Object error) { 83 | setState(() { 84 | _barcodeString = "Barcode: error"; 85 | _barcodeSymbology = "Symbology: error"; 86 | _scanTime = "At: error"; 87 | }); 88 | } 89 | 90 | void startScan() { 91 | setState(() { 92 | _sendDataWedgeCommand( 93 | "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "START_SCANNING"); 94 | }); 95 | } 96 | 97 | void stopScan() { 98 | setState(() { 99 | _sendDataWedgeCommand( 100 | "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "STOP_SCANNING"); 101 | }); 102 | } 103 | 104 | @override 105 | Widget build(BuildContext context) { 106 | return new Scaffold( 107 | appBar: new AppBar( 108 | title: new Text("DataWedge Flutter"), 109 | ), 110 | body: Container( 111 | child: Row(children: [ 112 | Expanded( 113 | child: Column( 114 | children: [ 115 | Container( 116 | padding: const EdgeInsets.all(32), 117 | child: Row( 118 | children: [ 119 | Expanded( 120 | /*1*/ 121 | child: Column( 122 | crossAxisAlignment: CrossAxisAlignment.start, 123 | children: [ 124 | /*2*/ 125 | Container( 126 | padding: const EdgeInsets.only(bottom: 8), 127 | child: Text( 128 | '$_barcodeString', 129 | style: TextStyle( 130 | fontWeight: FontWeight.bold, 131 | ), 132 | ), 133 | ), 134 | Container( 135 | padding: const EdgeInsets.only(bottom: 8), 136 | child: Text( 137 | '$_barcodeSymbology', 138 | style: TextStyle( 139 | color: Colors.grey[500], 140 | ), 141 | ), 142 | ), 143 | Text( 144 | '$_scanTime', 145 | style: TextStyle( 146 | color: Colors.deepPurple, 147 | ), 148 | ), 149 | ], 150 | ), 151 | ), 152 | ], 153 | ), 154 | ), 155 | GestureDetector( 156 | // When the child is tapped, show a snackbar. 157 | onTapDown: (TapDownDetails) { 158 | //startScan(); 159 | startScan(); 160 | }, 161 | onTapUp: (TapUpDetails) { 162 | stopScan(); 163 | }, 164 | // The custom button 165 | child: Container( 166 | margin: EdgeInsets.all(8.0), 167 | padding: EdgeInsets.all(22.0), 168 | decoration: BoxDecoration( 169 | color: Colors.blue, 170 | borderRadius: BorderRadius.circular(8.0), 171 | ), 172 | child: Center( 173 | child: Text( 174 | "SCAN", 175 | style: TextStyle( 176 | fontWeight: FontWeight.bold, 177 | ), 178 | ), 179 | )), 180 | ), 181 | ], 182 | ), 183 | ), 184 | ])), 185 | ); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /datawedge_flutter/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.6.1" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.15.0" 46 | cupertino_icons: 47 | dependency: "direct main" 48 | description: 49 | name: cupertino_icons 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.0.3" 53 | fake_async: 54 | dependency: transitive 55 | description: 56 | name: fake_async 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.2.0" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | matcher: 71 | dependency: transitive 72 | description: 73 | name: matcher 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "0.12.10" 77 | meta: 78 | dependency: transitive 79 | description: 80 | name: meta 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "1.3.0" 84 | path: 85 | dependency: transitive 86 | description: 87 | name: path 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.8.0" 91 | sky_engine: 92 | dependency: transitive 93 | description: flutter 94 | source: sdk 95 | version: "0.0.99" 96 | source_span: 97 | dependency: transitive 98 | description: 99 | name: source_span 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.8.1" 103 | stack_trace: 104 | dependency: transitive 105 | description: 106 | name: stack_trace 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.10.0" 110 | stream_channel: 111 | dependency: transitive 112 | description: 113 | name: stream_channel 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "2.1.0" 117 | string_scanner: 118 | dependency: transitive 119 | description: 120 | name: string_scanner 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.1.0" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.2.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.3.0" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.3.0" 145 | vector_math: 146 | dependency: transitive 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.1.0" 152 | sdks: 153 | dart: ">=2.12.0 <3.0.0" 154 | -------------------------------------------------------------------------------- /datawedge_flutter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: datawedgeflutter 2 | description: Accessing DataWedge from a Flutter app 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.12.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | 24 | # The following adds the Cupertino Icons font to your application. 25 | # Use with the CupertinoIcons class for iOS style icons. 26 | cupertino_icons: ^1.0.3 27 | 28 | dev_dependencies: 29 | flutter_test: 30 | sdk: flutter 31 | 32 | # For information on the generic Dart part of this file, see the 33 | # following page: https://dart.dev/tools/pub/pubspec 34 | 35 | # The following section is specific to Flutter. 36 | flutter: 37 | 38 | # The following line ensures that the Material Icons font is 39 | # included with your application, so that you can use the icons in 40 | # the material Icons class. 41 | uses-material-design: true 42 | 43 | # To add assets to your application, add an assets section, like this: 44 | # assets: 45 | # - images/a_dot_burr.jpeg 46 | # - images/a_dot_ham.jpeg 47 | 48 | # An image asset can refer to one or more resolution-specific "variants", see 49 | # https://flutter.dev/assets-and-images/#resolution-aware. 50 | 51 | # For details regarding adding assets from package dependencies, see 52 | # https://flutter.dev/assets-and-images/#from-packages 53 | 54 | # To add custom fonts to your application, add a fonts section here, 55 | # in this "flutter" section. Each entry in this list should have a 56 | # "family" key with the font family name, and a "fonts" key with a 57 | # list giving the asset and other descriptors for the font. For 58 | # example: 59 | # fonts: 60 | # - family: Schyler 61 | # fonts: 62 | # - asset: fonts/Schyler-Regular.ttf 63 | # - asset: fonts/Schyler-Italic.ttf 64 | # style: italic 65 | # - family: Trajan Pro 66 | # fonts: 67 | # - asset: fonts/TrajanPro.ttf 68 | # - asset: fonts/TrajanPro_Bold.ttf 69 | # weight: 700 70 | # 71 | # For details regarding fonts from package dependencies, 72 | # see https://flutter.dev/custom-fonts/#from-packages 73 | -------------------------------------------------------------------------------- /datawedge_flutter/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:datawedgeflutter/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /screenshots/app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/app.jpg -------------------------------------------------------------------------------- /screenshots/dw-profile-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/dw-profile-1.jpg -------------------------------------------------------------------------------- /screenshots/dw-profile-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/dw-profile-2.jpg -------------------------------------------------------------------------------- /screenshots/dw-profile-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/dw-profile-3.jpg -------------------------------------------------------------------------------- /screenshots/dw-profiles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/dw-profiles.jpg -------------------------------------------------------------------------------- /screenshots/google-flutter-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZebraDevs/DataWedge-Flutter-Demo/1e2130f6a6f2a1f4f254c306b7523460a50aa8de/screenshots/google-flutter-logo.png --------------------------------------------------------------------------------