{"id":23174082,"url":"https://github.com/zebradevs/datawedge-flutter-demo","last_synced_at":"2025-08-18T09:30:47.656Z","repository":{"id":42570914,"uuid":"250272054","full_name":"ZebraDevs/DataWedge-Flutter-Demo","owner":"ZebraDevs","description":"Demo application to show basic barcode capture in Flutter apps using DataWedge on Zebra devices","archived":false,"fork":false,"pushed_at":"2024-03-20T19:06:55.000Z","size":241,"stargazers_count":54,"open_issues_count":10,"forks_count":28,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-24T07:22:09.955Z","etag":null,"topics":["community","datawedge","demo","flutter"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ZebraDevs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-26T13:53:15.000Z","updated_at":"2024-04-20T01:53:22.000Z","dependencies_parsed_at":"2022-09-02T12:30:40.939Z","dependency_job_id":null,"html_url":"https://github.com/ZebraDevs/DataWedge-Flutter-Demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZebraDevs%2FDataWedge-Flutter-Demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZebraDevs%2FDataWedge-Flutter-Demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZebraDevs%2FDataWedge-Flutter-Demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZebraDevs%2FDataWedge-Flutter-Demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ZebraDevs","download_url":"https://codeload.github.com/ZebraDevs/DataWedge-Flutter-Demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230220149,"owners_count":18192223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["community","datawedge","demo","flutter"],"created_at":"2024-12-18T05:19:07.112Z","updated_at":"2024-12-18T05:19:07.601Z","avatar_url":"https://github.com/ZebraDevs.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"*Please be aware that this application / sample is provided as-is for demonstration purposes without any guarantee of support*\n=========================================================\n\n# DataWedge Flutter Demo\n\nOver 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.\n\n**This demo application shows how to interface to Zebra's DataWedge service from a Flutter application**\n\nFor 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.\n\n## Prerequisites\n\nYou 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\n\n```\nInstall flutter\n\u003eflutter run\nOptionally: Configure the Flutter SDK in Android Studio and run your application from there\n```\n\n## Sample Application\n\nThis 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).\n\nThe sample works as follows:\n- 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.\n- 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/). \n\n![Sample application](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/app.jpg)\n\nAs 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* \n\n## User Interface (Dart) code to receive data (e.g. scans) from DataWedge\n\nScanned 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.\n\n```dart\nstatic const EventChannel scanChannel = \n  EventChannel('com.darryncampbell.datawedgeflutter/scan');\n\n@override\nvoid initState() {\n  super.initState();\n  scanChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);\n}\n\nvoid _onEvent(Object event) {\n  setState(() {\n    Map barcodeScan = jsonDecode(event);\n    _barcodeString = \"Barcode: \" + barcodeScan['scanData'];\n    _barcodeSymbology = \"Symbology: \" + barcodeScan['symbology'];\n    _scanTime = \"At: \" + barcodeScan['dateTime'];\n  });\n}\n```\n\n## Native (Kotlin) code to handle scans received from DataWedge\n\nScan 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.\n\n```kotlin\nprivate val PROFILE_INTENT_ACTION = \"com.darryncampbell.datawedgeflutter.SCAN\"\nprivate val SCAN_CHANNEL = \"com.darryncampbell.datawedgeflutter/scan\"\n\nEventChannel(flutterEngine.dartExecutor, SCAN_CHANNEL).setStreamHandler(\n    object : StreamHandler {\n        private var dataWedgeBroadcastReceiver: BroadcastReceiver? = null\n        override fun onListen(arguments: Any?, events: EventSink?) {\n            dataWedgeBroadcastReceiver = createDataWedgeBroadcastReceiver(events)\n            val intentFilter = IntentFilter()\n            intentFilter.addAction(PROFILE_INTENT_ACTION)\n            registerReceiver(\n                dataWedgeBroadcastReceiver, intentFilter)\n        }\n\n        override fun onCancel(arguments: Any?) {\n            unregisterReceiver(dataWedgeBroadcastReceiver)\n            dataWedgeBroadcastReceiver = null\n        }\n    }\n)\n```\n\nReceived barcodes are parsed from the Intent into a 'Scan' object.  The stringified JSON representation of this Scan is sent over the EventChannel.\n\n```kotlin\nprivate fun createDataWedgeBroadcastReceiver(events: EventSink?): BroadcastReceiver? {\n    return object : BroadcastReceiver() {\n        override fun onReceive(context: Context, intent: Intent) {\n            if (intent.action.equals(PROFILE_INTENT_ACTION))\n            {\n                //  A barcode has been scanned\n                var scanData = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_DATA_STRING)\n                var symbology = intent.getStringExtra(DWInterface.DATAWEDGE_SCAN_EXTRA_LABEL_TYPE)\n                var date = Calendar.getInstance().getTime()\n                var df = SimpleDateFormat(\"dd/MM/yyyy HH:mm:ss\")\n                var dateTimeString = df.format(date)\n                var currentScan = Scan(scanData, symbology, dateTimeString);\n                events?.success(currentScan.toJson())\n            }\n            //  Could handle return values from DW here such as RETURN_GET_ACTIVE_PROFILE\n            //  or RETURN_ENUMERATE_SCANNERS\n        }\n    }\n}\n```\n\n## User Interface (Dart) code to send commands to DataWedge\n\nThe 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. \n\nThe 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.\n\n```dart\nstatic const MethodChannel methodChannel =\n    MethodChannel('com.darryncampbell.datawedgeflutter/command');\n\nFuture\u003cvoid\u003e _sendDataWedgeCommand(String command, String parameter) async {\n  try {\n    String argumentAsJson = \"{\\\"command\\\":$command,\\\"parameter\\\":$parameter}\";\n    await methodChannel.invokeMethod(\n          'sendDataWedgeCommandStringParameter', argumentAsJson);\n  } on PlatformException {\n    //  Error invoking Android method\n  }\n}\n```\n\nHandler for the onTouchDown event, initiate the scan when the button is pressed.  Calls the above function with the appropriate DataWedge API command and parameter.\n\n```dart\nvoid startScan() {\n  setState(() {\n    _sendDataWedgeCommand(\n        \"com.symbol.datawedge.api.SOFT_SCAN_TRIGGER\", \"START_SCANNING\");\n  });\n}\n```\n\n## Native (Kotlin) code to send commands to DataWedge\n\nParse 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.\n\n```kotlin\nMethodChannel(flutterEngine.dartExecutor, COMMAND_CHANNEL).setMethodCallHandler { call, result -\u003e\n    if (call.method == \"sendDataWedgeCommandStringParameter\")\n    {\n        val arguments = JSONObject(call.arguments.toString())\n        val command: String = arguments.get(\"command\") as String\n        val parameter: String = arguments.get(\"parameter\") as String\n        sendCommandString(applicationContext, command, parameter)\n    }\n    else {\n        result.notImplemented()\n    }\n}\n\nfun sendCommandString(context: Context, command: String, parameter: String) {\n    val dwIntent = Intent()\n    dwIntent.action = \"com.symbol.datawedge.api.ACTION\"\n    dwIntent.putExtra(command, parameter)\n    context.sendBroadcast(dwIntent)\n}\n```\n### DataWedge Configuration\n\nAs 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.\n\nIf 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.\n\n![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profiles.jpg)\n![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-1.jpg)\n![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-2.jpg)\n![DataWedge configuration](https://raw.githubusercontent.com/darryncampbell/DataWedgeFlutter/master/screenshots/dw-profile-3.jpg)\n\n## Not covered by this sample\n\nThis is a very basic sample designed to only show the basics of capturing data in a Flutter app on a Zebra Android device.\n\nMany 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. \n\nMany 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.  \n\n## Contributing\nThis 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.\n\n## License\nThis project is released under the [MIT](LICENSE) license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzebradevs%2Fdatawedge-flutter-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzebradevs%2Fdatawedge-flutter-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzebradevs%2Fdatawedge-flutter-demo/lists"}