Monday, December 29, 2014

Using ftdi_sio with linux kernel 3.12 and up

A few years ago I did post some informations on how to use a Bixolon BCD-1100 or a Epson DM-D110 displays attached via USB to a linux system.

This works fine, unless you upgrade your Linux system to a kernel with version 3.12 or greater.

Since Kernel 3.12 you will see this in the logs:
# dmesg
ftdi_sio: unknown parameter 'vendor' ignored
ftdi_sio: unknown parameter 'product' ignored 



The problem is, that these two parameters where only intended to be used by developers for testing purposes. So they have now been removed from the 3.12 kernel.
But fortunaly, the linux guys did provide a official way to specify the vendor and product ID's.

We can find it in the file: /sys/bus/usb-serial/drivers/ftdi_sio/new_id.
This file contains a pair of vendor and product id, so all we need is to put those values into this file, doing something like this:

/sbin/modprobe ftdi_sio
echo "1208 0780" > /sys/bus/usb-serial/drivers/ftdi_sio/new_id


If you wish to have it automatically configured, just update your /etc/udev/rules.d/50-dmd110.rules file as follows:

ATTR{idProduct}=="0780", ATTR{idVendor}=="1208", RUN+="/sbin/modprobe -q ftdi_sio" RUN+="/bin/sh -c 'echo 1208 0780 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'",  OWNER="root", MODE="0666"

or for the /etc/udev/rules.d/51-bixolonBCD1100.rules

ATTR{idVendor}=="1504", ATTR{idProduct}=="0011", RUN+="/sbin/modprobe -q ftdi_sio"  RUN+="/bin/sh -c 'echo 1504 0011 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'",  OWNER="root", MODE="0666"

or for the  /etc/udev/rules.d/52-star-bcd122u.rules
ATTR{idVendor}=="0519", ATTR{idProduct}=="0007", RUN+="/sbin/modprobe -q ftdi_sio"  RUN+="/bin/sh -c 'echo 0519 0007 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'",  OWNER="root", MODE="0666"

Please note that you still need to use the correct serial port settings.
The bcd122u for example runs at 19200 baud as where most others are using 9600 baud.

Monday, November 24, 2014

Monitoring HTTPS (and other SSL) certificates with Zabbix

In this year, we had a lot of security issues with SSL certificates, mostly in HTTPS, but also in other protocols using TLS/SSL.

The most serious concern is the poodle attack on SSLv3 connections.
The recommended setting is to disable SSLv3 in all your services.

The other issue is, that SHA1 is deprecated for HTTPS certificates, especially when the certificate expiration date is after 1. january 2017.
Google (and other web browser software developper) will gradually tell you, that
the certificates are not thrustworthy or even invalid.

You will find a lot of links in the web how to secury your server systems against poodle, and also on how to renew your certificates, so they don't use SHA1 anymore.

But how to make sure all your systems are correctly configured and the certificates in a valid range?
With Zabbix this is very simple, I have made a Zabbix template available, so you can integrate monitoring and alerting of SSL certificates in Zabbix.

You can download the Zabbix Template(s) and the ssl/tls check script from this link.
  1. Place the ssltls.check script in your zabbix external script folder and make it executable.
  2. Then import the template(s) and assign them to your server(s).
The HTTPS Template checks on Port 443 for the SSL things we described above. In addition it also checks the expirationdate and hash of your certificate.

The FTP template checks if TLS is activated on your FTP server and then checks for correct ssl working. It does no hash and 2017 expiration checks, since this is only relevant for webbrowsers.
The POP_IMAP_SMTP template checks if TLS is activae on POP,IMAP,SMTP,SMTP Submission and the POP3/IMAPS and SMTP services. It does no hash and 2017 expiration checks, since this is only relevant for webbrowsers.

The ssl check script is based on a version from Simon Kowallik, I did extend it to
also be able to check for the digest algorithm and detect the poodle vulnerability.

Link for SSLv3 disabling on various server products

Thursday, September 25, 2014

Don't write boilerplate code for java objects any longer

When you write java classes, you usually have many properties you expose via getter/setter methods.
This gives a lot of code, which is not very interesting to write and maintain, but for the sake of java bean (and other reasons) you will do it correctly.

It's one of the features of the IDE that you can let them generate the proper getter/setter methods.
Usually it's called something like "Encapsulate property access". You then select the properties you wish setter/getter created and you are done, the idea puts the correct code in your class.

Nice, but, it could be simpler.
The drawback of all this is, that you fill up your class file with a lot of set/get code which you usually don't want to see.

Fortunally there is help for this as well.
Look at the project Lombook.

With this project you write your class like this:

01 import lombok.AccessLevel;
02 import lombok.Setter;
03 import lombok.Data;
04 import lombok.ToString;
05
06 @Data public class DataExample {
07   private final String name;
08   @Setter(AccessLevel.PACKAGEprivate int age;
09   private double score;
10   private String[] tags;
11   
12   @ToString(includeFieldNames=true)
13   @Data(staticConstructor="of")
14   public static class Exercise<T> {
15     private final String name;
16     private final T value;
17   }
18 }
 
These 18 lines of code do the same as these 118 lines of plain java coding:
001 import java.util.Arrays;

002
003 public class DataExample {
004   private final String name;
005   private int age;
006   private double score;
007   private String[] tags;
008   
009   public DataExample(String name) {
010     this.name = name;
011   }
012   
013   public String getName() {
014     return this.name;
015   }
016   
017   void setAge(int age) {
018     this.age = age;
019   }
020   
021   public int getAge() {
022     return this.age;
023   }
024   
025   public void setScore(double score) {
026     this.score = score;
027   }
028   
029   public double getScore() {
030     return this.score;
031   }
032   
033   public String[] getTags() {
034     return this.tags;
035   }
036   
037   public void setTags(String[] tags) {
038     this.tags = tags;
039   }
040   
041   @Override public String toString() {
042     return "DataExample(" this.getName() ", " this.getAge() ", " this.getScore() ", " + Arrays.deepToString(this.getTags()) ")";
043   }
044   
045   protected boolean canEqual(Object other) {
046     return other instanceof DataExample;
047   }
048   
049   @Override public boolean equals(Object o) {
050     if (o == thisreturn true;
051     if (!(instanceof DataExample)) return false;
052     DataExample other = (DataExampleo;
053     if (!other.canEqual((Object)this)) return false;
054     if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
055     if (this.getAge() != other.getAge()) return false;
056     if (Double.compare(this.getScore(), other.getScore()) != 0return false;
057     if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
058     return true;
059   }
060   
061   @Override public int hashCode() {
062     final int PRIME = 59;
063     int result = 1;
064     final long temp1 = Double.doubleToLongBits(this.getScore());
065     result = (result*PRIME(this.getName() == null this.getName().hashCode());
066     result = (result*PRIMEthis.getAge();
067     result = (result*PRIME(int)(temp1 ^ (temp1 >>> 32));
068     result = (result*PRIME+ Arrays.deepHashCode(this.getTags());
069     return result;
070   }
071   
072   public static class Exercise<T> {
073     private final String name;
074     private final T value;
075     
076     private Exercise(String name, T value) {
077       this.name = name;
078       this.value = value;
079     }
080     
081     public static <T> Exercise<T> of(String name, T value) {
082       return new Exercise<T>(name, value);
083     }
084     
085     public String getName() {
086       return this.name;
087     }
088     
089     public T getValue() {
090       return this.value;
091     }
092     
093     @Override public String toString() {
094       return "Exercise(name=" this.getName() ", value=" this.getValue() ")";
095     }
096     
097     protected boolean canEqual(Object other) {
098       return other instanceof Exercise;
099     }
100     
101     @Override public boolean equals(Object o) {
102       if (o == thisreturn true;
103       if (!(instanceof Exercise)) return false;
104       Exercise<?> other = (Exercise<?>o;
105       if (!other.canEqual((Object)this)) return false;
106       if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
107       if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
108       return true;
109     }
110     
111     @Override public int hashCode() {
112       final int PRIME = 59;
113       int result = 1;
114       result = (result*PRIME(this.getName() == null this.getName().hashCode());
115       result = (result*PRIME(this.getValue() == null this.getValue().hashCode());
116       return result;
117     }
118   }
119 }
 
 
 
 
So with project lombok you can concentrate on the real code, and the annotations do expand on build to the boilerplate code.
There are many options in lombok to also generate other things for java classes, be sure to look at the documentation.

There is just one "bad" thing about it:
By definition annotations should not create java code, but in this case I think it is worth the "break" of rules.

Thursday, August 28, 2014

Moving files into the azure cloud

Microsoft azure cloud provides SMB 2.1 file server functionality.

This is great when you need to access your files from different VM or services,
since don't need to run your own VM with the fileserver role installed.

As a bonus, you can access your files also via REST service, so your are very flexible in the usage of the service.

A introduction to the fileserver functionality can be found in this blog post.

When you have setup your service correctly, it's time to move some data to it.
The simplest approach would be to use xcopy or a similar tool to upload your files into the azure file service.

The drawback of such standard tools is, that they copy the files sequencially, one by one.
Azure is a cloud which provides massive paralell operations, so there is a faster way to get your file into the cloud.

Microsoft has released a tool named AzCopy which allows you to upload whole folders in paralell, which will speedup your uploads.

In this blog post there are more examples and use cases to bring your files into the Azure cloud.

Thursday, August 21, 2014

Using "related" fields/properties in vaadin tables with JPA containers

Vaadin is a Java framework for building modern web applications that look great, perform well and make you and your users happy.

It has a lot of features which help you in building data driven applications, without having to code everything yourself.
As with any powerfull frameworks you often come to a plcae where a "simple" thing isn't that simple to implement.
Perhaps the framework is just not prepared for that simple feature you wish to use, or you don't find the way to use it correctly.

Vaadin has containers which allow you do present data in forms and tables, without needing to code everything yourself.
There exist different types of containers, depending on your original data source, for example you can have SQL database, Bean objects and many others as a source.

With the JPA container, you can use to handle then whole data stuff with JPA.
So you could for example use hibernate or eclispelink to back your java objects in a sql database.

There is a whole chapter in the book of vaadin describing the JPA container.
When you have a object which has relations to other objects, then you can also specify the JPA container about such "related" properties or fields.
For example when you have a Person object, which has a relation to a country object, you can teel the JPA container about the additional fields available from the Country object.

// Have a persistent container
JPAContainer<Person> persons =
    JPAContainerFactory.make(Person.class, "book-examples");

// Add a nested property to a many-to-one property
persons.addNestedContainerProperty("country.name");
        
// Show the persons in a table, except the "country" column,
// which is an object - show the nested property instead
Table personTable = new Table("The Persistent People", persons);
personTable.setVisibleColumns(new String[]{"name","age",
                                           "country.name"});


// Have a nicer caption for the country.name column
personTable.setColumnHeader("country.name", "Nationality");


The Vaadin JPA container automagically knows to go via the object/database relation and retrieve the correct values.

When you use the filtering table add on available from the vaadin add ons, you can also implement filters on these additional fields.

For this you have to implement the FilterGenerator interface and then tell the table which properties are handled with this filter.
Of course your filter code must then generate the correct filter criterias.

@Override
public Container.Filter generateFilter(Object propertyId, Object value)
{
    if ("country.name".equals(propertyId))
    {
        if (value != null && value instanceof String)
        {
            return new Like("name", value.toString()+"%");
        }
    }
}


Tuesday, August 19, 2014

Free eBook about Ethernet Layer 2 encryption

You can download the free  2014 edition of Layer 2 Ethernet by Christoph Jaggi (published by inside-IT.ch) for your devices.
The book is best viewed on a tablet or computer.
Though you can tap them to expand to full size, there are many graphics which may be difficult to read on smaller devices, such as smartphones.

Go to the download page

For more about Christoph Jaggi, visit www.uebermeister.com or send an email.

Friday, July 11, 2014

130 free ebooks available from Microsoft

Microsoft has many many free ebooks available for download on their different websites.
Up to now it was difficult to find them, since they are scattered over the different sites and pages.

Thanks to Eric Ligman we now have a (complete?) list of all available free ebooks from microsoft.
The books are available in different formats, most are pdf, some are epub or mobi and even some word and zip documents are available.
Some of the ebooks are also available in multiple formats, just look at them.



The books cover MS related topics, from Windows 7, to Server 2012, Sharepoint, SQL Server and many other related topis.

You can also get a free info app, where new free ebooks will be announced.
Unfortunally this one is only available for Windows Phone...

Wednesday, July 2, 2014

What rectangular selection can be used for in Netbeans

Netbeans has very powerfull editing capabilities.
One of the less known features is the regular selection in text files.

This is very handy, when you for example need to remove the first two columns inside a text file.

Go to the first line, press CTRL+SHIFT+R and move the cursor down to then end and left two characters.
This selects the first two character in each line.


Now with a single DEL key you can remove them all.

But there is more to this rectangular stuff...
With the rectangular selection still active, start typing hello

Here what you get...


As you see, not only deletion of text can be made via rectangular selection, but also inserting new text on multiple lines at the same time.

This is handy, when you for example wish to add a css class to a lot of <div> tags at the idention level.

A improved version of this multi row editing capability is sheduled for a upcomming version of netbeans. The corresponding enhancement request can be found here.

Official Office 365 Roadmap available

Microsoft recently published a roadmap for the office 365 environment.
You can look at it here.

It shows what has already been rolled out, what is currently in the rolling out phase and what is intended to be implemented/changed in the next weeks/months.

New features are not released for all office 365 at the same time.
Rather the new functionality is rolled out in several phases, during a few days up to a few months, depending on the impact of the changes.

Tuesday, June 24, 2014

Office 365 public folders reject emails

Since two days mails to Office 365 (and probably MS hosted exchange too) are rejected.

The error message returned by the server have this error in them:

Remote Server returned '550 5.7.1 RESOLVER.RST.AuthRequired; authentication required [Stage: CreateMessage]'

 It seems that MS did change some policy/settings in the public folder management and did forgot to inform users and sys admins.

In non-hosted exchange environments, you had to set the CreateItem right on the email enabled public folders which should be able to receive (external) emails.
In office365 this was not required until a few days ago.

There are two ways to set the corresponding rights. For me, the way via Outlook did not work, since I did not see the ACL on the public folders in question.
But the way via PowerShell works just fine.

Do it the easy way (if it works)

Just open outlook and go to your email enabled folder(s) and do add the CreateMessage right for Anonymous access, as show in the following two printscreens.






If this does not work (or you have a lot of email enabled public folders), then you have to ressort to PowerShell

Do it via PowerShell

1. Start powershell as administrator (Only required if you need to change the execution policy )
2. Set the execution policy to allow signed remote code

Set-ExecutionPolicy RemoteSigned

3. Enter credentials for office365

$LiveCred = Get-Credential

4. Make a connection to office365

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection

5. Import the cloud commands in your local powershell

Import-PSSession $Session –AllowClobber

6. Now set the CreateMessage right on all public folders recursively

Get-PublicFolder "\" -Recurse | Add-PublicFolderClientPermission -User Anonymous -AccessRights CreateItems
  
This changes the rights for all public folders. If you wish to set the right only for one public folder, thenyou can do it the same way, but instead of using the command in setp 6, you speicfy this command:

Add-PublicFolderClientPermission <path-to-folder> -User Anonymous -AccessRights createitems

Wednesday, June 4, 2014

Office 365 activation error 0x80070005

When you install Office 365 and then start it, it might occure that the error messages 0x80070005 is shown and you are unable to activate it.

Usually you don't have to activate Office 365, since it is already "bound" to your online account.
So Office is automatically activated.



When you see this dialog, then there is a problem with rights on your system.
The simplest way to solve the problem is to run Word or Excel once as administrator.
Just right click on word and then select "Run as administrator" and you won't even see the activation stuff. It will be activated in the background and after closing word you just can use the office 365 suite as usual.

Monday, June 2, 2014

App development with GWT, Cordova and Netbeans Part 4

This is the forth part of my blog series on how to develop mobile apps with GWT, Cordova and Netbeans. The initial description can be found here.
In the previous parts we did create a MGWT project and did put a "Hello world" button on the screen and finaly did build the native apps for android and windows phone.

Web apps are all nice, but often you wish to access some features of your mobile device which is not available to web applications. Some common things are the camera, sensors and so on.

With cordova/phonegap we fortunally can use these devices via native plugins.
Just a warning: Any plugin you use must be available on all target platforms, otherwise you will get in troubles. (There are ways to handle such situations, but they are outside the scope of this tutorial)

The first step to allow such access, is to teel the maven pom.xml that we wish to use phonegap "features".
Just add this dependency in your pom.xml file:

<dependency>
    <groupId>com.googlecode.gwtphonegap</groupId>
    <artifactId>gwtphonegap</artifactId>
    <version>2.4.0.0</version>
</dependency>


The second think to change, is you index.html file.
There you have to specify that cordova.js is started, so the html<->native bridge is activated.

Somewhere in your index.html you have the line which starts the gwt java script.
It looks like this:
<script type="text/javascript" language="javascript" src="mgwt1/mgwt1.nocache.js"></script>

Before that line, add the call to the cordova.js file, so the phonegap environment is initialized.

It should then look like this:

<script type="text/javascript" language="javascript" src="cordova.js"></script>
<script type="text/javascript" language="javascript" src="mgwt1/mgwt1.nocache.js"></script>

It is important that the cordova.js in loaded before the GWT script, because the initialisation order is important.

Finally you must tell the phonegap build service to include some native plugins, otherwise the cordova.js will be missing in the package.
For this add these lines to your src/main/phonegap-build/config.xml:

<feature name="http://api.phonegap.com/1.0/notification"/>
<feature name="http://api.phonegap.com/1.0/device"/>
<gap:plugin name="org.apache.cordova.device" version="0.2.8" />
<gap:plugin name="org.apache.cordova.dialogs" version="0.2.6" />

With these four lines you include the device information features (You can retrieve the platform informations) and show native notifications.

In the start() method of your "java" class, you add the initialisation of the phonegap environment.

PhoneGap phoneGap = GWT.create(PhoneGap.class);
boolean isPhoneGap= phoneGap.isPhoneGapDevice();
           
if (isPhoneGap)
{
    phoneGap.addHandler(new PhoneGapAvailableHandler()
    {
        @Override
        public void onPhoneGapAvailable(PhoneGapAvailableEvent event)
        {
            // Here you have the native "bridge" up and running
        }
    });
   phoneGap.addHandler(new PhoneGapTimeoutHandler()
   {
       @Override
       public void onPhoneGapTimeout(PhoneGapTimeoutEvent event) 
       {
           //can not start phonegap - something is for with your setup
       }
    });
}
The last step required, is tell GWT to use the phonegap API too.
So in your <project.gwt.xml uncomment this line:

<inherits name="com.googlecode.gwtphonegap.PhoneGap"/>

With this you now have access to all the features as described here.
Of course you need to speicfy access rights for you app, otherwise you will not be allowed to interact with the native phone system. (Camera etc.)

You can download the sample project from this place.

I hope you enjoyed this tutorial.
If you struggle somewhere, please drop me a note, so I can enhance the tutorial.


App development with GWT, Cordova and Netbeans Part 3

This is the first part of my blog series on how to develop mobile apps with GWT, Cordova and Netbeans. The initial description can be found here.
In the previous parts we did create a MGWT project and did put a "Hello world" button on the screen.
This is shown just nice on any browser, but is not yet a native mobile app.
In this part we will use the adobe phonegap build service to package our small web app as a native app which can be put in a app store of the big players.
Packaging the app for the different target systems is a tedious work, since you must install the different SDK, in the correct versions. And you can't develop all version on a single platform. For example iOS apps need a OS-X system to build them.

Fortunally there exists a build service from adobe which allows you to upload your web app as zip file (or take the source from a git repository) and then build the app for all the target platforms you wish.

The free version of the service allows you to build one private app and as many opensource apps as you wish.
If you need to build more private (or better closed source ) apps, then you can buy a upgrade for $9.99/Month which allows you to build up to 25 private applications.

We will continue with the free account and use this to build our closed source app, directly from inside netbeans. So you won't have to upload the zip file manually and can fully automate your builds.

The first step to build a native app, is extending the maven build to include the build service. Fortunally Chris has written a maven plugin which handles this very well.

In your pom.xml you just add the dependency to the new plugin:

<plugin>
    <groupId>com.github.chrisprice</groupId>
    <artifactId>phonegap-build-maven-plugin</artifactId>
    <version>0.0.7</version>
    <executions>
        <execution>
            <id>phonegap-build</id>
            <goals>
                <goal>clean</goal>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
   
    <platforms>            
            <!-- <platform>ios</platform> -->
       
    <platform>android</platform> 
            <platform>winphone</platform>
        </platforms>
    </configuration>                                   
</plugin>

With this your build process will push the zip file to the adobe build service and retrieve the final platform packages.
Since the build service is password protected, you need to specify your credentials.

This can simply be done by specifying which server should be used for building in your pom.xml file. (Almost on top of it)

<properties>
    <gwtversion>2.5.0</gwtversion>
    <phonegap-build.server>phonegap-build</phonegap-build.server>
</properties>

The second part is to specify your personal credentials. As it's a bad idea to put them in the pom.xml, you should put them in default maven settings file.
The maven settings file is called settings.xml and is usually located in the .m2 directory of the users home folder.

The content should look like this:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>phonegap-build</id>
            <username>yourlogin@adobe.com</username>
            <password>MySecurePassword</password>
        </server>
    </servers>
</settings>



The last step before starting the build is to specify a config.xml file, to instruct the build service what should be done.
This file is located under src/main/phonegap-build and should have this content:

<?xml version="1.0" encoding="UTF-8"?>
    <widget xmlns = "http://www.w3.org/ns/widgets"
        xmlns:gap = "http://phonegap.com/ns/1.0"
        id        = "org.company.project"
        versionCode=""
        version   = "1.0.0">
        <name>My test project</name>
        <description></description>
        <author href="http://www.aarboard.ch" email="support@aarboard.ch">André Schild</author>
        <preference name="phonegap-version" value="3.4.0" />
        <preference name="orientation" value="default" />
        <preference name="fullscreen" value="true" />
        <preference name="target-device" value="universal" />
        <preference name="webviewbounce" value="true" />
        <preference name="prerendered-icon" value="true" />
        <preference name="stay-in-webview" value="true" />
        <preference name="ios-statusbarstyle" value="black-opaque" />
        <preference name="detect-data-types" value="true" />
        <preference name="exit-on-suspend" value="true" />
        <preference name="show-splash-screen-spinner" value="true" />
        <preference name="auto-hide-splash-screen" value="true" />
        <preference name="EnableViewportScale" value="false" />
        <preference name="MediaPlaybackRequiresUserAction" value="false" />
        <preference name="AllowInlineMediaPlayback" value="false" />
        <preference name="BackupWebStorage" value="cloud" />
        <preference name="TopActivityIndicator" value="gray" />
        <preference name="KeyboardDisplayRequiresUserAction" value="true" />
        <preference name="HideKeyboardFormAccessoryBar" value="false" />
        <preference name="SuppressesIncrementalRendering" value="false" />
        <preference name="android-minSdkVersion" value="7" />
        <preference name="android-installLocation" value="auto" />
        <preference name="SplashScreenDelay" value="5000" />
        <preference name="ErrorUrl" value=""/>
        <preference name="BackgroundColor" value=""/>
        <preference name="KeepRunning" value="false"/>
        <preference name="DisallowOverscroll" value="false"/>
        <preference name="LoadUrlTimeoutValue" value="20000" />
        <preference name="disable-cursor" value="true" />
        <gap:platform name="android" />
        <gap:platform name="winphone" />
        <access origin="http://127.0.0.1*" />
    </widget>


You can now rebuild your project and should have the two app packages in the target/phonegap-build folder.
One is a .apk file for android, the other a .xap file for windows phone.

You could now transfer these files to your mobile device and test them, or you can go to the adobe build service page and scan the QR code from there.


If you modify your code, you can then just rebuild the app and reinstall it on your phone.
If subsequent builds fail, then you have to specify which APP number to use. Otherwise the build service thinks you wish to cretae multiple private apps.

To prevent this, you note the app id from the build service (see screenshot above) and then add this to your pom.xml file in the plugin section.

    </platforms>
    <appId>9xxxxxx</appId>                            </configuration>                   

As you may have noted, we did now build the app for Android and Windows phone. When you wish to build your app for iOS, then you need a developer account from apple. This account costs $99.-/Year.
You have to create a account here and then register for iOS development. You will then receive a signing key, with which you have to sign ANY iOS application you develop. There is no other way to install software on your iOS devices (unless you root the device)

In the next and last part of the serie we will look at what is required to access native features for your mobile device. In short you need to integrate the cordova plugins and initialize them correctly.