How to import platform specific file in flutter? - javascript

I am using JS package for Flutter to JS communication and vice versa.
It's working fine when I try to run on the web but giving errors when trying to run in the mobile emulator.
I am trying this
import 'package:flutter/material.dart'
if(dart.library.jqyery) 'common.dart';
But that starts giving errors on all the functions which are in file common. dart
This is common. dart
#JS()
library jquery;
import 'globals.dart';
import 'package:js/js.dart';
#JS('myCallDartToJSFunction')
external void myAlert(String str);
#JS('connectToSignalR')
external void connectToSignalR();
#JS("mySendMsgTSignalR")
external void myDartSendMsgTSignalR(String nam, String msg);
#JS('myCallJSToDart')
external set _myCallJSToDart(void Function(String str, int x) f);
#JS()
external void myCallJSToDart(String str, int x);
void _someDartFunction(String str, int x) {
print(str + x.toString());
msgFromSignalr = str;
}
#JS('messageFromSignalR')
external set _messageFromSignalR(void Function(String str) f);
#JS()
external void messageFromSignalR();
String _dartmessageFromSignalR(String str) {
}
void bindmain() {
_myCallJSToDart = allowInterop((text, x) => _someDartFunction(text, x));
_messageFromSignalR = allowInterop((str) => _dartmessageFromSignalR(str));
}

In your example you are importing flutter/material.dart when you are on mobile which won't be accepted as a valid replacement for common.dart. When doing conditionnal imports you should always provide 2 identical implementations. In your case it means making a file, for example, common_mobile.dart which will implement the same methods that are in your common.dart but doing nothing (or even throwing an UnimplementedException) as they should not be called while you are on mobile.
I see that you are making a library inside your common.dart which is not recommended if you want to keep both a mobile and a web implementation as you would have 2 library with the same name.
A conditionnal import should be done as follow:
import 'common_mobile.dart'
if (dart.library.js) 'common.dart' as commonUtils;
In this sample I am importing by default the file common_mobile.dart but if I am on the web version (which can be verified with if (dart.library.js)) I am importing common.dart. I am adding the as commonUtils keyword to secure my calls to my import.
Now to make a call myAlert for example:
/// Making a web verification to ensure your call is only done when running on web.
if (kIsWeb) {
/// It should call the myAlert implementation from common.dart
commonUtils.myAlert('Test');
}
Moreover I am seeing that your package does not support mobile which means that if there is build errors related to your package directly you won't be able to build on mobile no matter what you do and your only option is to separate your project into 2 branches (one mobile only and the other one web only) to remove packages that only supports only a specific platform.

Related

How can I pass data via a Word document from a Java-Server to a JS Add-In?

What I want to do is storing data on the server-side inside a word document using Java and Apache POI and read that data from inside a Word Add-In written in JavaScript. (On a sidenote: Personally I'm only working on the JS part of this, the Java part is done by someone else.)
Now, I need to support Word 2016 on Windows which means I cannot use WordApi requirement sets 1.3 and 1.2. This means that (as far as I can tell) I cannot use Custom Properties, which would be perfect. An alternative I've found are Custom XML Parts. But this is where I'm stuck right now.
We found this solution for the Java part: Add Custom XML Part using Apache POI
But I don't know how I can read that data using the JavaScript APIs. There are two functions to read "Custom XML Parts": (accessible through the object Office.context.document.customXmlParts) getByIdAsync() and getByNamespaceAsync() (both are documented here). Even after unzipping the generated word document I can see the added custom XML, so writing works fine. But there is no ID (which should be a GUID according to the docs) nor a namespace. So, I don't know how I can access this data.
Are both sides talking about the same type of "Custom XML Parts"? And how can I achieve my goal? I'm open to all kind of solutions: Using a different JS API, different Java API, or both.
Based on this question another POI user provided me an example .docx. Find below the POI code to generate a .docx containing CustomXML elements, which can be selected via VBA.
The GUID can be used to retrieve the CustomXMLPart via the SelectByID method
The customXml XmlBeans used below need the poi-ooxml-full artifact instead of the default poi-ooxml-lite artifact.
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CUSTOM_PROPERTIES;
import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CUSTOM_XML;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.apache.poi.ooxml.POIXMLProperties;
import org.apache.poi.ooxml.POIXMLTypeLoader;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.junit.jupiter.api.Test;
import org.openxmlformats.schemas.officeDocument.x2006.customProperties.CTProperty;
import org.openxmlformats.schemas.officeDocument.x2006.customXml.CTDatastoreItem;
import org.openxmlformats.schemas.officeDocument.x2006.customXml.DatastoreItemDocument;
public class TestCustomXML {
private static final String CUSTOM_DOCPROP_TYPE = "application/vnd.openxmlformats-officedocument.custom-properties+xml";
private static final String CUSTOM_PROP_TYPE = "application/vnd.openxmlformats-officedocument.customXmlProperties+xml";
private static final String CUSTOM_PROP_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
private interface PartWriter {
void write(Writer os) throws IOException;
}
#Test
public void addXml() throws InvalidFormatException, IOException {
// Generate GUID
final String guid = java.util.UUID.randomUUID().toString().toUpperCase();
try (XWPFDocument doc = new XWPFDocument();
FileOutputStream fos = new FileOutputStream("customxml.docx")) {
PackagePart partItm =
createPart(doc, "/customXml/item1.xml", ContentTypes.PLAIN_OLD_XML, doc.getPackagePart(), CUSTOM_XML, (osw) -> {
osw.write("<myxml><foo>baa</foo></myxml>");
});
DatastoreItemDocument did = DatastoreItemDocument.Factory.newInstance();
CTDatastoreItem di = did.addNewDatastoreItem();
di.setItemID(guid);
di.addNewSchemaRefs();
createPart(doc, "/customXml/itemProps1.xml", CUSTOM_PROP_TYPE, partItm, CUSTOM_PROP_REL, (osw) -> {
did.save(osw, POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
});
org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument custProp =
org.openxmlformats.schemas.officeDocument.x2006.customProperties.PropertiesDocument.Factory.newInstance();
CTProperty prop = custProp.addNewProperties().addNewProperty();
prop.setFmtid(POIXMLProperties.CustomProperties.FORMAT_ID);
prop.setName("mycustom_name_value");
prop.setPid(2);
prop.setLpwstr("1,2");
createPart(doc, "/docProps/custom.xml", CUSTOM_DOCPROP_TYPE, null, CUSTOM_PROPERTIES, (osw) -> {
custProp.save(osw, POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
});
doc.write(fos);
}
}
private static PackagePart createPart(XWPFDocument doc, String name, String contentType, PackagePart source, String relType, PartWriter writer)
throws InvalidFormatException, IOException {
PackagePartName ppn = PackagingURIHelper.createPartName(name);
OPCPackage opc = doc.getPackage();
PackagePart part = opc.createPart(ppn, contentType);
if (source == null) {
opc.addRelationship(ppn, TargetMode.INTERNAL, relType);
} else {
source.addRelationship(ppn, TargetMode.INTERNAL, relType);
}
try (OutputStream os = part.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
writer.write(osw);
}
return part;
}
}

Call javascript method from Cordova Plugin's service

I am currently developing an App using Cordova and therefore have developed a Cordova Plugin, that runs a service and is being started from within that plugin:
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
switch(action){
case "start":
Intent startIntent = new Intent(context, BackgroundService.class);
startIntent.putExtra("action", "play");
context.startService(startIntent);
return true;
}
return false;
}
The code is shortened for readability. Now normally I would use callbacks to call javascript methods from within the plugin, but as I want to use a service for the functionality, how could I call a method (or maybe the callback) from there?
Thank you very much in advance :).
Okay so I did not find a way to this with vanilla cordova, but this Plugin provides the functionality I was looking for: https://github.com/bsorrentino/cordova-broadcaster
You have to set up a LocalBroadcastManager in your native Android Code and send an Intent with it. You then define a bundle containg the data you want to send, and put it as extra of your intent. Then you send the intent via the broadcast manager and receive it via javascript.
Sample Java:
startCallback = new Intent("callback");
Bundle b = new Bundle();
b.putString("callback", "start");
startCallback.putExtras(b);
LocalBroadcastManager.getInstance(applicationContext).sendBroadcastSync(startCallback);
Sample Javascript:
var callbackListener = function( e ) {
console.log("What kind of callback: " + e.callback);
};
window.broadcaster.addEventListener( "callback", callbackListener);
I hope this helps somebody with a similiar problem :).

Selenium with headless chrome

I have testing environment which is perfectly working with chrome driver in desktop mode. I am using some javascript injections (everything works) f.e.:
public static void ForceFillInput(this Driver driver, string selector, string value)
{
var javaScriptExecutor = (IJavaScriptExecutor)driver.webDriver;
javaScriptExecutor.ExecuteScript($"$(\"{selector}\").val(\"{value}\")");
}
but when i want to run it in headless mode
AddArguments("--headless")
it will just fail on
"$ is not defined"
Can somebody help me how to inject js/jquery into headless solution?
M.
your Javascript snippet used jQuery api. In modern web development, we put Javascript at the end of HTML page to let browser to load javascript at last, so that static resources (like picture/image/text content) can display earlier as possible, withing this way to improve user experience when user open website.
I think your page also put jQuery at the end to load, try add some wait/sleep before ExecuteScript to wait browser complete load jQuery.
It looks like the shorthand for JQuery is not yet created at the time your script is executed.
Use a waiter to wait for JQuery and for the selector to be found:
public static void ForceFillInput(this Driver driver, string selector, string value)
{
string JS_SET_VALUE =
"var e; return !!window.$ && (e = window.$(arguments[0])).length > 0 && (e.val(arguments[1]), true);";
new WebDriverWait(driver, TimeSpan.FromSeconds(60))
.until(ctx => (bool)((IJavaScriptExecutor)ctx).ExecuteScript(JS_SET_VALUE, selector, value));
}

Is it possible to ignore JavaScript exceptions when working with WebDriver (HtmlUnit, Ruby bindings)

HtmlUnit throws exception and crash my test when I'm loading the page
caps = Selenium::WebDriver::Remote::Capabilities.htmlunit(:javascript_enabled => true)
driver = Selenium::WebDriver.for(:remote, :desired_capabilities => caps)
driver.navigate.то url
ReferenceError: "x" is not defined.
(net.sourceforge.htmlunit.corejs.javascript.EcmaError)
No exception is thrown if I use a Firefox driver.
caps = Selenium::WebDriver::Remote::Capabilities.firefox
Or disable JavaScript for HtmlUnit driver
caps = Selenium::WebDriver::Remote::Capabilities.htmlunit(:javascript_enabled => false)
I am unable to change the code on the test page and fix the problem, so I need to either ignore it or in any way to use Firefox JavaScript Engine instead of the standard HtmlUnit JavaScript Engine.
Is it possible to solve my problem without changing the code of test page?
Update:
Tried Capybara + WebKit as an alternative to Selenium + HtmlUnit - works fine, without errors. But still I would like to solve the problem without changing the framework.
For Java Only:
In the latest version of WebClient (which is wrapped by HTMLUnitDriver) client.setThrowExceptionOnScriptError(false) method is deprecated. In case of subclassing HTMLUnitDriver, you need to override modifyWebClient method:
public class MyHtmlUnitDriver extends HtmlUnitDriver {
...
#Override
protected WebClient modifyWebClient(WebClient client) {
//currently does nothing, but may be changed in future versions
WebClient modifiedClient = super.modifyWebClient(client);
modifiedClient.getOptions().setThrowExceptionOnScriptError(false);
return modifiedClient;
}
}
After looking at the source of the HtmlUnitDriver, it seems like there is no possibility to customize the behaviour you want to change. The easiest thing you could do to solve this is to patch and recompile the Selenium server (which might or might not be an option). You'd need to add this line:
--- HtmlUnitDriver.java 2012-01-05 17:45:22.779579136 +0100
+++ HtmlUnitDriver.java 2012-01-05 18:14:51.415106195 +0100
## -255,6 +255,7 ##
WebClient client = newWebClient(version);
client.setHomePage(WebClient.URL_ABOUT_BLANK.toString());
client.setThrowExceptionOnFailingStatusCode(false);
+ client.setThrowExceptionOnScriptError(false);
client.setPrintContentOnFailingStatusCode(false);
client.setJavaScriptEnabled(enableJavascript);
client.setRedirectEnabled(true);
I was able to solve it using HPUnit_Extensions_Selenium2TestCase v1.4.0 as follows:
class TestBase extends PHPUnit_Extensions_Selenium2TestCase
{
public function setUp()
{
$this->setHost(<your-host>);
$this->setPort(<your-port>);
$this->setDesiredCapabilities(Array("javascriptEnabled"=>"false"));
Based on answer from #Vitaly
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import com.gargoylesoftware.htmlunit.WebClient;
import java.util.logging.Logger;
import java.util.logging.Level;
public class MyHtmlUnitDriver extends HtmlUnitDriver {
protected void modifyWebClient() {
/* turn off annoying htmlunit warnings */
Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
WebClient newWebClient = getWebClient();
newWebClient.getOptions().setThrowExceptionOnScriptError(false);
newWebClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
newWebClient.getOptions().setPrintContentOnFailingStatusCode(false);
modifyWebClient(newWebClient);
}
}
I found the same problem in the .net world.
I got around it in c# by using reflection and an extension method:
public static void SetThrowOnScriptErrors(this HtmlUnitDriver driver,
bool throwScriptErrors )
{
object webClient = driver.GetType().InvokeMember("_webClient",
BindingFlags.GetField |
BindingFlags.NonPublic |
BindingFlags.Instance, null,
driver, new object[0]);
webClient.GetType().InvokeMember("throwExceptionOnScriptError_",
BindingFlags.SetField |
BindingFlags.NonPublic |
BindingFlags.Instance,
null, webClient,
new object[] {throwScriptErrors});
}
This method wil shut up any logger for always!
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
setFinalStatic(com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.class.getDeclaredField("LOG"), new org.apache.commons.logging.Log() {
});

Getting MAC address on a web page using a Java applet

I want to create an application where a web server can get the MAC Address of the clients logging in. The only possible way I could think of was to create a JAVA applet which contains java.net methods to find the mac address
I am using javascript to call the applet methods, but the browser is not allowing those methods to execute. Below is the applet I have created.
import java.applet.*;
import java.awt.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
public class AppletRunner extends Applet{
// The method that will be automatically called when the applet is started
public void init()
{
// It is required but does not need anything.
}
//This method gets called when the applet is terminated
//That's when the user goes to another page or exits the browser.
public void stop()
{
// no actions needed here now.
}
//The standard method that you have to use to paint things on screen
//This overrides the empty Applet method, you can't called it "display" for example.
public void paint(Graphics g)
{
//method to draw text on screen
// String first, then x and y coordinate.
g.drawString(getMacAddr(),20,20);
g.drawString("Hello World",20,40);
}
public String getMacAddr() {
String macAddr= "";
InetAddress addr;
try {
addr = InetAddress.getLocalHost();
System.out.println(addr.getHostAddress());
NetworkInterface dir = NetworkInterface.getByInetAddress(addr);
byte[] dirMac = dir.getHardwareAddress();
int count=0;
for (int b:dirMac){
if (b<0) b=256+b;
if (b==0) {
macAddr=macAddr.concat("00");
}
if (b>0){
int a=b/16;
if (a==10) macAddr=macAddr.concat("A");
else if (a==11) macAddr=macAddr.concat("B");
else if (a==12) macAddr=macAddr.concat("C");
else if (a==13) macAddr=macAddr.concat("D");
else if (a==14) macAddr=macAddr.concat("E");
else if (a==15) macAddr=macAddr.concat("F");
else macAddr=macAddr.concat(String.valueOf(a));
a = (b%16);
if (a==10) macAddr=macAddr.concat("A");
else if (a==11) macAddr=macAddr.concat("B");
else if (a==12) macAddr=macAddr.concat("C");
else if (a==13) macAddr=macAddr.concat("D");
else if (a==14) macAddr=macAddr.concat("E");
else if (a==15) macAddr=macAddr.concat("F");
else macAddr=macAddr.concat(String.valueOf(a));
}
if (count<dirMac.length-1)macAddr=macAddr.concat("-");
count++;
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
macAddr=e.getMessage();
} catch (SocketException e) {
// TODO Auto-generated catch block
macAddr = e.getMessage();
}
return macAddr;
}
}
Applets cannot normally access these functions for security reasons. To avoid these restrictions, you need a signed applet, along with a policy file.
You can then write a policy file which grants your applet access to the functionality it needs. If the user then grants your applet the necessary permissions (it will prompt for them), your applet can use the functions.
In Netbeans, you can sign an application enabling the WebStart:
Access to Your project > properties > Application > WebStart
Check "Enable Web Start". This show a sectin titled signing.
Click the "Customize" button located in the signing section.
Select "self-sign by generated key".
I don't think this will be possible. Web servers communicate with clients several layers above the link layer where MAC addresses live -- it's abstracted away by TCP/IP and there's no reason for the client to send it unless you specifically have client code to do that.
The reason your Java code isn't working is because the Java sandbox's security manager disallows such low-level calls -- which it should! If you ever do find a way to get that thing to work (which I doubt you will) you should promptly report it to Oracle because it shouldn't be happening at all.
I can't see much of a reason why you'd want it either, to be honest.
The Java applet is prevented to access those methods on the client because it runs in a protected sandbox.
It might not be possible within a browser, since it is against the sandboxing paradigm. You might have some luck with browser-specific native code extensions.
However, the important exception is if your web server is in the same local area network (same switch) as the client - then, the MAC address of the client is known to the server because it is still present in the IP packet.

Categories