Skip to content

Commit

Permalink
Merge pull request #21 from andriyoganp/fix/webcontent-converter-plat…
Browse files Browse the repository at this point in the history
…form-channel

fix: content to image native code
  • Loading branch information
andriyoganp authored Dec 3, 2021
2 parents 380ed17 + a893ee0 commit dead958
Show file tree
Hide file tree
Showing 16 changed files with 510 additions and 182 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.0.8

* Add native code to convert content image

## 0.0.7

* Add parameter option to generate image as raster
Expand Down
175 changes: 150 additions & 25 deletions android/src/main/kotlin/com/ayeee/blue_print_pos/BluePrintPosPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,36 +1,161 @@
package com.ayeee.blue_print_pos

import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.WindowInsets
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
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
import io.flutter.plugin.common.PluginRegistry.Registrar
import java.io.ByteArrayOutputStream
import kotlin.math.absoluteValue

/** BluePrintPosPlugin */
class BluePrintPosPlugin: 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(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "blue_print_pos")
channel.setMethodCallHandler(this)
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
result.notImplemented()
}
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
class BluePrintPosPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
/// 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
private lateinit var activity: Activity
private lateinit var context: Context
private lateinit var webView: WebView

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val viewID = "webview-view-type"
flutterPluginBinding.platformViewRegistry.registerViewFactory(viewID, FLNativeViewFactory())

channel = MethodChannel(flutterPluginBinding.binaryMessenger, "blue_print_pos")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.applicationContext
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
val arguments = call.arguments as Map<*, *>
val content = arguments["content"] as String
val duration = arguments["duration"] as Double?

if (call.method == "contentToImage") {
webView = WebView(this.context)
val dWidth: Int
val dHeight: Int
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics = activity.windowManager.currentWindowMetrics
val insets = windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
dWidth = windowMetrics.bounds.width() - insets.left - insets.right
dHeight = windowMetrics.bounds.height() - insets.bottom - insets.top
} else {
dWidth = this.activity.window.windowManager.defaultDisplay.width
dHeight = this.activity.window.windowManager.defaultDisplay.height
}
print("\ndwidth : $dWidth")
print("\ndheight : $dHeight")
webView.layout(0, 0, dWidth, dHeight)
webView.loadDataWithBaseURL(null, content, "text/HTML", "UTF-8", null)
webView.setInitialScale(1)
webView.settings.javaScriptEnabled = true
webView.settings.useWideViewPort = true
webView.settings.javaScriptCanOpenWindowsAutomatically = true
webView.settings.loadWithOverviewMode = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
print("\n=======> enabled scrolled <=========")
WebView.enableSlowWholeDocumentDraw()
}

print("\n ///////////////// webview setted /////////////////")

webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)

Handler(Looper.getMainLooper()).postDelayed({
print("\nOS Version: ${Build.VERSION.SDK_INT}")
print("\n ================ webview completed ==============")
print("\n scroll delayed ${webView.scrollBarFadeDuration}")

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("document.body.offsetWidth") { offsetWidth ->
webView.evaluateJavascript("document.body.offsetHeight") { offsetHeight ->
print("\noffsetWidth : $offsetWidth")
print("\noffsetHeight : $offsetHeight")
val data = webView.toBitmap(
offsetWidth!!.toDouble(),
offsetHeight!!.toDouble()
)
if (data != null) {
val bytes = data.toByteArray()
result.success(bytes)
println("\n Got snapshot")
}
}
}
}
}, duration!!.toLong())
}
}
} else {
result.notImplemented()
}
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
print("onAttachedToActivity")
activity = binding.activity
webView = WebView(activity.applicationContext)
webView.minimumHeight = 1
webView.minimumWidth = 1
}

override fun onDetachedFromActivityForConfigChanges() {
// TODO: the Activity your plugin was attached to was destroyed to change configuration.
// This call will be followed by onReattachedToActivityForConfigChanges().
print("onDetachedFromActivityForConfigChanges")
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
// TODO: your plugin is now attached to a new Activity after a configuration change.
print("onAttachedToActivity")
onAttachedToActivity(binding)
}

override fun onDetachedFromActivity() {
// TODO: your plugin is no longer associated with an Activity. Clean up references.
print("onDetachedFromActivity")
}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

fun WebView.toBitmap(offsetWidth: Double, offsetHeight: Double): Bitmap? {
if (offsetHeight > 0 && offsetWidth > 0) {
val width = (offsetWidth * this.resources.displayMetrics.density).absoluteValue.toInt()
val height = (offsetHeight * this.resources.displayMetrics.density).absoluteValue.toInt()
this.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
this.draw(canvas)
return bitmap
}
return null
}

fun Bitmap.toByteArray(): ByteArray {
ByteArrayOutputStream().apply {
compress(Bitmap.CompressFormat.PNG, 100, this)
return toByteArray()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.ayeee.blue_print_pos

import android.content.Context
import android.view.View
import android.webkit.WebView
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class FLNativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return FLNativeView(context, viewId, creationParams)
}
}


internal class FLNativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
private val webView: WebView = WebView(context)
private var arguments: Map<String?, Any?>? = creationParams

override fun getView(): View {
return webView
}

override fun dispose() {}

init {
var width = (arguments!!["width"]!! as Number).toInt()
var height = (arguments!!["height"]!! as Number).toInt()
var content = arguments!!["content"] as String
webView.layout(0, 0, width, height)
webView.loadDataWithBaseURL(null, content, "text/HTML", "UTF-8", null)
webView.setInitialScale(1)
webView.settings.javaScriptEnabled = true
webView.settings.useWideViewPort = true
webView.settings.javaScriptCanOpenWindowsAutomatically = true
webView.settings.loadWithOverviewMode = true


}

}
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
<string>9.0</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion example/ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
2 changes: 1 addition & 1 deletion example/ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
16 changes: 8 additions & 8 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
PODS:
- blue_print_pos (0.0.1):
- Flutter
- blue_thermal_printer (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_blue (0.0.1):
- Flutter
Expand All @@ -9,14 +11,12 @@ PODS:
- Flutter
- Protobuf (~> 3.11.4)
- Protobuf (3.11.4)
- webcontent_converter (0.0.1):
- Flutter

DEPENDENCIES:
- blue_print_pos (from `.symlinks/plugins/blue_print_pos/ios`)
- blue_thermal_printer (from `.symlinks/plugins/blue_thermal_printer/ios`)
- Flutter (from `Flutter`)
- flutter_blue (from `.symlinks/plugins/flutter_blue/ios`)
- webcontent_converter (from `.symlinks/plugins/webcontent_converter/ios`)

SPEC REPOS:
trunk:
Expand All @@ -25,20 +25,20 @@ SPEC REPOS:
EXTERNAL SOURCES:
blue_print_pos:
:path: ".symlinks/plugins/blue_print_pos/ios"
blue_thermal_printer:
:path: ".symlinks/plugins/blue_thermal_printer/ios"
Flutter:
:path: Flutter
flutter_blue:
:path: ".symlinks/plugins/flutter_blue/ios"
webcontent_converter:
:path: ".symlinks/plugins/webcontent_converter/ios"

SPEC CHECKSUMS:
blue_print_pos: 23e8b4bede0fc07cd75b3257783523ca332bf3cb
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
blue_thermal_printer: e0f989c1ba2cae289f6472ebae0a22611958f2bc
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_blue: eeb381dc4727a0954dede73515f683865494b370
Protobuf: 176220c526ad8bd09ab1fb40a978eac3fef665f7
webcontent_converter: baa47c5fc5a9e8d703897a0b128f969c58fd2c7f

PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d

COCOAPODS: 1.10.1
COCOAPODS: 1.10.2
3 changes: 1 addition & 2 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 51;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -121,7 +121,6 @@
4CEB8AF9736A2F8D716546E1 /* Pods-Runner.release.xcconfig */,
E5D7780485383C04BB7F6B16 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand Down
Loading

0 comments on commit dead958

Please sign in to comment.