I have a problem with my application on iOS only (iPad 9.7" 11.3.1), it works perfectly on the simulator and on Android device.
When the app is launched for the first time, the user has to log in. This works fine. After that, the menu form is launched and a Dialog is shown on onShowCompleted():
if (!Preferences.get("download", false)) {
dialog = new Dialog("...");
dialog.setLayout(new BorderLayout());
SpanLabel label = new SpanLabel("...");
dialog.addComponent(BorderLayout.CENTER, label);
dialog.show(Display.getInstance().getDisplayHeight() / 5, ..., ..., ...);
}
In the constructor, a method that downloads informations is launched :
if (!Preferences.get("download", false)) {
dlReferentiel();
}
The method :
public void dlReferentiel() {
source = DataSource.getInstance();
// I also tried with invokeAndBlock() but doesn't work
/*
Display.getInstance().invokeAndBlock(() -> requestS());
Display.getInstance().invokeAndBlock(() -> requestB());
Display.getInstance().invokeAndBlock(() -> requestZ());
Display.getInstance().invokeAndBlock(() -> requestA());
*/
requestS();
requestB();
requestZ();
requestA();
}
The requestX methods get informations from server with ConnectionRequest :
(Exemple with requestA() which needs to be the last because it disposes the dialog, it is the only one that calls the UI)
public void requestA() {
ConnectionRequest connectionRequest = new ConnectionRequest() {
ArrayList<A> as = new ArrayList<>();
#Override
protected void readResponse(InputStream in) throws IOException {
JSONParser json = new JSONParser();
Reader reader = new InputStreamReader(in, "UTF-8");
Map<String, Object> data = json.parseJSON(reader);
for (String s : data.keySet()) {
as.add(new A(s, (String) data.get(s)));
}
}
#Override
protected void postResponse() {
source.createAllA(as); // makes insertions with Transaction
ToastBar.showErrorMessage("Référentiel téléchargé", 10);
dialog.dispose();
Preferences.set("download", true);
}
};
connectionRequest.setUrl(URL_A);
connectionRequest.setPost(true);
NetworkManager.getInstance().addToQueue(connectionRequest);
}
I was able to see some logs with a Mac. Each time, the app crashes after the Dialog is shown and few insertions are made. The same error message is output :
HW kbd: Failed to set (null) as keyboard focus
Unable to get short BSD proc info for 513: No such process
Unable to get proc info for 513: Undefined error: 0
I search for informations about this issue but nothing interesting with Codename One.
I don't know what to do with this error, I tried some things like using invokeAndBlock() or changing build hints like ios.keyboardOpen (just because there is "keyboard" in it) but nothing worked.
Thanks for the help.
Related
I try to use this librairy to use the barcode scanner on iOS : https://github.com/codenameone/cn1-codescan It works very well on Android but when my application opens the same barcode scanner form on iOS, my application just shuts down without displaying any error message.
I have to scan Code 128 bar codes.
Perhaps that I have to edit the property especially for IOS ?
Here is my code :
public class ScanCode extends Form {
final Container cnt = this;
public ScanCode(Form parent){
this.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Display.getInstance().setProperty("android.scanTypes", "CODE_128");
CodeScanner.getInstance().scanBarCode(new ScanResult() {
public void scanCompleted(String contents, String formatName, byte[] rawBytes) {
String word;
word= contents.substring(0,12);
List<Patient> myList= new ArrayList<>();
myList= RestManager.getList(contents.substring(0,12));
if(myList.size()==0){
new ManualInfo(parent,contents).show();
}
else{
Date date = new Date();
Intervention intervention = new Intervention();
intervention.setList(myList.get(0));
intervention.setDateAction(date);
intervention.setDateCreate(date);
intervention.setDateUpdate(date);
intervention.setEncodingType(Intervention.BARCODE_TYPE);
Update ajoutintervention = new Update();
ajoutintervention.setId((long) 0);
ajoutintervention.setDatas(intervention.toJson());
ajoutintervention.setDateCreate(date);
ajoutintervention.setDateUpdate(date);
ajoutintervention.setTreatment(String.valueOf(Constants.INSERT));
ajoutintervention.setDone(String.valueOf(false));
ajoutintervention.setClassName(intervention.getName());
ajoutintervention.setParam(myList.get(0).getWord());
DatabaseHelper.saveDataClass(ajoutintervention);
}
}
public void scanCanceled() {
cnt.addComponent(new Label("cancelled"));
}
public void scanError(int errorCode, String message) {
cnt.addComponent(new Label("err " + message));
}
});
}
EDIT:
Here is the build hints :
codename1.arg.ios.add_libs=ExternalAccessory.framework;CoreBluetooth.framework;libc++.dylib;SystemConfiguration.framework;,libc++.dylib,CoreText.framework,MessageUI.framework,CoreVideo.framework,CoreMedia.framework
codename1.arg.ios.background_modes=,bluetooth-central,bluetooth-peripheral
codename1.arg.ios.debug.archs=arm64
codename1.arg.ios.includePush=true
codename1.arg.ios.newStorageLocation=true
codename1.arg.ios.plistInject=<key>NSBluetoothPeripheralUsageDescription</key><string>This app uses a BLE cardreader</string><key>UISupportedExternalAccessoryProtocols</key><array><string>bt.reader.library</string></array> <key>NSAppTransportSecurity</key> <dict><key>NSAllowsArbitraryLoads</key><true/></dict>
codename1.arg.ios.pods.platform=8.0,7.0
codename1.arg.ios.pods.sources=https\://github.com/CocoaPods/Specs.git
codename1.arg.ios.xcode_version=10.1
codename1.arg.java.version=8
I work on a 12.1 iOS version and the device is an iPad Air.
Make sure your cn1lib is up to date and that you ran it on the simulator as well. You need to define the ios.NSCameraUsageDescription build hint (or codename1.arg.ios.NSCameraUsageDescription if you edit the file directly). This is required by current versions of iOS. The library adds this implicitly when you run the code in the simulator.
I face strange execution behaviors in login test methods. I run this code Under selenium Grid. and Grid is configured as a standalone server. So, first I start the selenium grid(Hub\Node) using the batch file to execute by tests.
Following is my class and specs.
code:
1. pojDataSource.java:
public class pojDataSource {
private static WebElement element = null;
private static List<WebElement> elements = null;
public static WebElement txt_UserName(WebDriver driver){
driver.findElement(By.id("txtUserName")).clear();
element = driver.findElement(By.id("txtUserName"));
return element;
}
public static WebElement txt_Password(WebDriver driver){
driver.findElement(By.id("txtPassword")).clear();
element = driver.findElement(By.id("txtPassword"));
return element;
}
}
clsConstant.java:
public class clsConstant {
public static final String URL = "http://localhost:1234/";
public static final String Username = "username";
public static final String Password = "password";
}
ModuleTest.java:
public class ModuleTest {
public RemoteWebDriver mDriver = null;
public DesiredCapabilities mCapability = new DesiredCapabilities() ;
public WebElement mWebElement = null;
public String mBaseURL = clsConstant.URL;
public static clsExcelSampleData mAddConnectorXls;
#Test
public void beforeMethod() throws Exception {
WebDriverWait wdw =null;
mCapability.setCapability("platform", org.openqa.selenium.Platform.WINDOWS);
mCapability = DesiredCapabilities.firefox();
mCapability.setVersion("45.0.2");
mDriver = new RemoteWebDriver(new URL("http://127.0.0.1:4444/wd/hub/"), mCapability);
mDriver.get(mBaseURL);
mDriver.manage().window().maximize();
pojDataSource.txt_UserName(mDriver).sendKeys(clsConstant.Username ) ;
pojDataSource.txt_Password(mDriver).sendKeys(clsConstant.Password ) ;
pojDataSource.btn_LogIn(mDriver).click();
}
When I execute the code in DEBUG mode in eclipese IDE it shows me the strange behaviors. First it start browser and open the mBaseURL successful with login screen. After loading page it shows default userName\password in browser.
Now when debug point comes to pojDataSource.txt_UserName(mDriver).sendKeys(clsConstant.Username ); line. By pressing F5 my debug point goes to pojDataSource.txt_Password(); line and it fetch wrong password and script execution fails. I worry about how this will be happens if my debug point is at username but still it goes to fetch value of password?
Tried solutions:
1. As I use Firefox browser to run test. I clear my password from browser catch.
Recheck the WebElements IDs and make sure they are reachable by WebDriver while debugging. Also try to avoid using 'static' to WebElements. Take a look on Page Objects Pattern.
I have a WebBrowser control on a form, but for the most part it remains hidden from the user. It is there to handle a series of login and other tasks. I have to use this control because there is a ton of Javascript that handles the login. (i.e., I can't just switch to a WebClient object.)
After hopping around a bit, we end up wanting to download a PDF file. But instead of downloading, the file is displayed within the webBrowser control, which the user can not see.
How can I download the PDF instead of having it load in the browser control?
Add a SaveFileDialog control to your form, then add the following code on your WebBrowser's Navigating event:
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (e.Url.Segments[e.Url.Segments.Length - 1].EndsWith(".pdf"))
{
e.Cancel = true;
string filepath = null;
saveFileDialog1.FileName = e.Url.Segments[e.Url.Segments.Length - 1];
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
filepath = saveFileDialog1.FileName;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(e.Url, filepath);
}
}
}
//Callback function
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("File downloaded");
}
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d338a2c8-96df-4cb0-b8be-c5fbdd7c9202
The solution I ended up using:
I did everything else as-needed to get the URL where it needed to go. Knowing that all of the login information, required settings, viewstates, etc. were stored in the cookies, I was finally able to grab the file using a hybrid of the web control to navigate then the WebClient object to actually snag the file bytes.
public byte[] GetPDF(string keyValue)
{
DoLogin();
// Ask the source to generate the PDF. The PDF doesn't
// exist on the server until you have visited this page
// at least ONCE. The PDF exists for five minutes after
// the visit, so you have to snag it pretty quick.
LoadUrl(string.Format(
"https://www.theMagicSource.com/getimage.do?&key={0}&imageoutputformat=PDF",
keyValue));
// Now that we're logged in (not shown here), and
// (hopefully) at the right location, snag the cookies.
// We can use them to download the PDF directly.
string cookies = GetCookies();
byte[] fileBytes = null;
try
{
// We are fully logged in, and by now, the PDF should
// be generated. GO GET IT!
WebClient wc = new WebClient();
wc.Headers.Add("Cookie: " + cookies);
string tmpFile = Path.GetTempFileName();
wc.DownloadFile(string.Format(
"https://www.theMagicSource.com/document?id={0}_final.PDF",
keyValue), tmpFile);
fileBytes = File.ReadAllBytes(tmpFile);
File.Delete(tmpFile);
}
catch (Exception ex)
{
// If we can't get the PDF here, then just ignore the error and return null.
throw new WebScrapePDFException(
"Could not find the specified file.", ex);
}
return fileBytes;
}
private void LoadUrl(string url)
{
InternalBrowser.Navigate(url);
// Let the browser control do what it needs to do to start
// processing the page.
Thread.Sleep(100);
// If EITHER we can't continue OR
// the web browser has not been idle for 10 consecutive seconds yet,
// then wait some more.
// ...
// ... Some stuff here to make sure the page is fully loaded and ready.
// ... Removed to reduce complexity, but you get the idea.
// ...
}
private string GetCookies()
{
if (InternalBrowser.InvokeRequired)
{
return (string)InternalBrowser.Invoke(new Func<string>(() => GetCookies()));
}
else
{
return InternalBrowser.Document.Cookie;
}
}
bool documentCompleted = false;
string getInnerText(string url)
{
documentCompleted = false;
web.Navigate(url);
while (!documentCompleted)
Application.DoEvents();
return web.Document.Body.InnerText;
}
private void web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
documentCompleted = true;
}
I read where someone was able to do this, but I'm having a hard time getting it to work.
Basically, I'm scheduling an HTTP callout to a page that has a controller that builds a CSV and emails it to a recipient.
The Scheduled class:
global class ReportExporter implements System.Schedulable {
global void execute(SchedulableContext sc) {
getmailReportOutput ex = new getmailReportOutput();
ex.exportCSV();
}
}
The getEmailReportOutput class:
public class getmailReportOutput{
public Static String strSessionID;
public getmailReportOutput() {
}
public void exportCSV() {
makeReportRequest();
}
#future (callout=true)
public Static void makeReportRequest() {
strHost ='c.cs4.visual.force.com';
strSessionID = UserInfo.getSessionId();
String requestUrl = 'https://' + strHost + '/apex/TestSendReport#';
HttpRequest req = new HttpRequest();
req.setEndpoint(requestUrl);
req.setMethod('GET');
req.setHeader('Cookie','sid=' + strSessionID );
String output = new Http().send(req).getBody();
System.debug('HTTP RESPONSE RETURNED: ' + output);
}
}
The getEmailReportOutput class does an HTTP Callout to a VF page: I make sure to send the sessionID with the request:
And the "TestSendReport" is just a simple callout to a controller:
<apex:page controller="Exporter" action="{!runrpt}">
</apex:page>
...And the controller is calling the report content:
public class Exporter {
public static Boolean isTest;
public static String strEmailAddr;
public void runrpt() {
executeRpt();
}
#future
public static void executeRpt() {
System.debug('CALLING REPORT EXPORTER...');
String ReportName__c = '00OP0000000Jp3N';
String strEmailAddr = 'myname#email.com';
ApexPages.PageReference report = new ApexPages.PageReference( '/' + RptName__c + '?csv=1');
Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment();
attachment.setFileName('report.csv');
attachment.setBody(report.getContent());
attachment.setContentType('text/csv');
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
message.setFileAttachments(new Messaging.EmailFileAttachment[] { attachment } );
message.setSubject('Report');
message.setPlainTextBody('The report is attached.');
message.setToAddresses( new String[] { strEmailAddr } );
Messaging.sendEmail( new Messaging.SingleEmailMessage[] { message } );
}
}
...Any ideas? The debug logs show all is well, but nothing is received. I know this is a wall of code, but it seems to be what people recommend to accomplish the task - I just can't see anything wrong.
I don't see anything obviously missing here :/
Just to be safe - getEmailReportOutput & getmailReportOutput are the same class (typo error in the post, not in your actual code)?
This looks like jumping a lot of hops, do I read it correctly that it's scheduled class -> REST callout -> VF page with action -> #future -> send an email? Geez, a lot can go wrong here ;) I've read somewhere that SF will keep some kind of reference counter and calling out to same instance might block you from using page.getContent...
Can you see the report body System.debug(report.getContent().toString());? Can you try saving this email as task for your own user or under a sample Account for example (setSaveAsActivity())?
As blatant plug as it is - I've used different path to solve similar requirement. Check out https://salesforce.stackexchange.com/questions/4303/scheduled-reports-as-attachment and see if you can get it to work?
I've had this code working for at least a year and today it threw an exception that i haven't been able to figure out why its happening. Its a Forms.WebBrowser that hits a generic site first and then a secondary site.
'first site
wbr.ScriptErrorsSuppressed = False
wbr.Navigate("http://www.bing.com/?rb=0")
Do
Application.DoEvents()
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
'second site
wbr.ScriptErrorsSuppressed = True
Dim start As DateTime = DateTime.Now
Dim loopTimeout As TimeSpan = TimeSpan.FromSeconds(timeout)
wbr.Navigate("http://www.FlightAware.com")
Do
Application.DoEvents()
'loop timer
If DateTime.Now.Subtract(start) > loopTimeout Then
'stop browser
wbr.Stop()
'throw exception
Dim eExpTme As Exception = New Exception("A loop timeout occurred in the web request.")
Throw eExpTme
End If
Loop Until wbr.ReadyState = WebBrowserReadyState.Complete
The error happens on the second site access and it shows that it errors on the very last line with
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Windows.Forms.UnsafeNativeMethods.IHTMLLocation.GetHref()
at System.Windows.Forms.WebBrowser.get_Document()
at System.Windows.Forms.WebBrowser.get_ReadyState()
I just don't get why its errorring on the second site and not the first and what exactly that error message means. I've looked at some help forums but nothing concrete that i can use to troubleshoot.
AGP
The web site has a frame on ad.doubleclick.net, by default cross-domain frame access is disabled for the internet zone, so you get a security exception.
Catch the exception and move on. There isn't much you need to care about in the frame, doubleclick is an ad service.
You can implement IInternetSecurityManager and let IE to believe ad.doubleclick.net and FlightAware.com are the same web site, but this can cause security problem if you extend the trust to arbitrary web sites.
Here is a little hack in C# which you can convert in Vb.net:
public class CrossFrameIE
{
// Returns null in case of failure.
public static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow)
{
if (htmlWindow == null)
{
return null;
}
// First try the usual way to get the document.
try
{
IHTMLDocument2 doc = htmlWindow.document;
return doc;
}
catch (COMException comEx)
{
// I think COMException won't be ever fired but just to be sure ...
if (comEx.ErrorCode != E_ACCESSDENIED)
{
return null;
}
}
catch (System.UnauthorizedAccessException)
{
}
catch
{
// Any other error.
return null;
}
// At this point the error was E_ACCESSDENIED because the frame contains a document from another domain.
// IE tries to prevent a cross frame scripting security issue.
try
{
// Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider.
IServiceProvider sp = (IServiceProvider)htmlWindow;
// Use IServiceProvider.QueryService to get IWebBrowser2 object.
Object brws = null;
sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);
// Get the document from IWebBrowser2.
IWebBrowser2 browser = (IWebBrowser2)(brws);
return (IHTMLDocument2)browser.Document;
}
catch
{
}
return null;
}
private const int E_ACCESSDENIED = unchecked((int)0x80070005L);
private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
}
// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}