DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Port Native Android App to iOS: Part II

Port Native Android App to iOS: Part II

Here in Part II, we will build the skeleton of the app.

Shai Almog user avatar by
Shai Almog
CORE ·
Oct. 15, 16 · Tutorial
Like (4)
Save
Tweet
Share
3.73K Views

Join the DZone community and get the full member experience.

Join For Free

In Part I of this series we discussed the port of Swiftnotes to iOS by porting it to Codename One and covered what Codename One is and how it differs from Android.

As a reminder, the finished app is on Apple iTunes, Google Play, and the Microsoft store as well as online with a JavaScript build which you can see here.

The full source code of the app is here: https://github.com/codenameone/SwiftnotesCN1

Porting Tool

A while back we announced an open source project to ease the porting process cn1 android importer. This is a very basic tool that just scaffolds the new Codename One project from an Android project without really duplicating the UI or converting the code.

We can obviously improve this tool significantly but to do so we need to gauge community interest which so far has been "underwhelming". I will start by using this tool as it is now to get started quickly and then port the code.

The Porting Process

First, we need to get the pre-requisites:

  • Download the Android importer from https://github.com/shannah/cn1-android-importer/blob/master/dist/ - note that at this time the files from the lib directory should also be downloaded but this should hopefully be resolved
  • Download and unzip the Swiftnotes sources from https://github.com/adrianchifor/Swiftnotes/archive/master.zip
  • Download NetBeans and install Codename One if you haven’t already

Step 1: Create a New Codename One Project

The instructions are for NetBeans but should work for IntelliJ as is. I’m not sure about Eclipse.

We create a standard Codename One project:

In the new project wizard we select Codename One Figure 1. In the new project wizard, we select Codename One

The project name doesn’t matter much I just used SwiftnotesCN1

The project name and location Figure 2. The project name and location

We then pick the class/package name, the package name should match the existing Android package name if you want to replace the original project. I also picked a native theme for simplicity and the barebone application to start from scratch:

We should use the same package name as the android project Figure 3. We should use the same package name as the android project

After doing this I chose to refactor the app to the com.codename1 package space so we can run it side by side with the native app

Step 2: Run the Conversion Tool

The conversion tool is very simplistic and preliminary. It had issues with some of the UI elements even with it’s limited support for these features.

If you show enough interest, file issues we’ll fix them and move this tool forward

I used the following command to convert the project:

java -jar AndroidImporter.jar import-project -i Swiftnotes-master/app/src/main/res -o ~/dev/SwiftnotesCN1 -p com.moonpi.swiftnotes

The first argument is the resource directory for the original Android project. Followed by the output directory (the new Codename One project) and the package name where GUI files should be created.

This placed the localization bundles and imported the images, it also generated the GUI XML files.

To generate the GUI sources right-click the project and select "build" this will generate GUI source files for all the XML files.

Step 3: Bind Localization Code

This is really trivial and will allow us to see something running almost at once, open the main class in our case SwiftnotesCN1. Edit the init(Object) method to load the localization Strings:

public void init(Object context) {
    theme = UIManager.initFirstTheme("/theme");

    Map<String, String> v = theme.getL10N("strings", L10NManager.getInstance().getLanguage());
    if(v == null) {
        v = theme.getL10N("strings", "en");
    }
    UIManager.getInstance().setBundle(v);

    // Enable Toolbar on all Forms by default
    Toolbar.setGlobalToolbar(true);

    // Pro only feature, uncomment if you have a pro subscription
    Log.bindCrashProtection(true);
}

To see/edit the Strings in the app double click the

theme.res

file in the root of the project and select the localization section.

Interlude: The GUI Builder

The wizard generates GUI builder XML files that are "hidden" under the res/guibuilder directory and must correspond to Java source files. They carry the .gui extension and use a relatively simple format of hierarchy/layout.

You can edit the XML files but if you remove the java files they will be regenerated. You need to remove/move the XML & Java files together if you want to work with both.

Currently, the generator doesn’t generate much as it can’t replicate the layout and Android is too different from Codename One, but it’s a starting point.

Step 4: Fix the Main Activity Form

The generated code derives from Container instead of Form since Android doesn’t have an equivalent of Codename One’s concept of a top level component. We can just edit the ActivityMain class to derive from Form instead of Container (you can also do that in the .gui XML file but it’s not essential).

We can now right-click the MainActivity.java file and select the GUI builder option which should open this UI:

Main Activity UI as it is generated Figure 4. Main Activity UI as it is generated

This looks a bit weird but if we look at the Android XML this starts to make sense:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    tools:context=".MainActivity"
    android:background="@color/background_white" >

    <include
        android:id="@+id/toolbarMain"
        layout="@layout/toolbar"/>

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/listView"
        android:divider="@null"
        android:dividerHeight="8dp"
        android:drawSelectorOnTop="true"
        android:fastScrollEnabled="true"
        android:scrollbarStyle="outsideOverlay"
        android:paddingRight="16dp"
        android:paddingLeft="16dp"
        android:clipToPadding="false"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/toolbarMain"
        android:paddingTop="8dp"
        android:paddingBottom="8dp" />

    <ImageButton
        android:layout_width="65dp"
        android:layout_height="65dp"
        android:id="@+id/newNote"
        android:scaleType="fitXY"
        android:background="@drawable/ic_new_selector"
        android:layout_marginBottom="30dp"
        android:layout_marginRight="30dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:contentDescription="@string/new_note_content_description" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/noNotes"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="@string/no_notes_text"
        android:textColor="@color/theme_primary"
        android:textStyle="bold"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"
        android:gravity="center"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_centerInParent="true"
        android:visibility="invisible" />

    <View
        android:layout_width="match_parent"
        android:layout_height="@dimen/shadow_elevation"
        android:layout_below="@+id/toolbarMain"
        android:layout_alignParentRight="true"
        android:layout_alignParentLeft="true"
        android:background="@drawable/drop_shadow" />

</RelativeLayout>

Above we have these elements:

  • Toolbar - this is builtin to Codename One with the Toolbar class
  • ListView - Codename One doesn’t recommend lists and instead uses box layout so we will use a Container
  • ImageButton & Shadow - this is used to provide the floating action button, this is builtin to Codename One
  • TextView - used to show content when the view is empty. We will have a special case for it in the Container

Notice that there is a toolbar.xml file included but it doesn’t include anything important just theme stuff and nothing of value to us.

All of these elements except for the text view are useless to us:

  • The Toolbar is built-in to Codename One
  • We should avoid lists and instead use BoxLayoutContainer
  • We have a built-in FloatingActionButton so we don’t need that.

So we will delete everything except for the text. We will also verify that the layout is BoxLayout.Y_AXIS (it should already be with that layout).

One important thing we need to do is select the root form and make sure its UIID property is Form otherwise the converter will try to assign the default UIID’s from Android which won’t work well.

After removing all the redundant stuff... Figure 5. After removing all the redundant stuff…

We save and open the Java source file, then edit the constructor to include the FloatingActionButton as well as the proper title. So we change this:


public ActivityMain(com.codename1.ui.util.Resources resourceObjectInstance) {
    initGuiBuilderComponents(resourceObjectInstance);
}

To this:

public ActivityMain(com.codename1.ui.util.Resources resourceObjectInstance) {
    super("app_name");

    initGuiBuilderComponents(resourceObjectInstance);

    FloatingActionButton fab = FloatingActionButton.createFAB(FontImage.MATERIAL_ADD);
    fab.bindFabToContainer(getContentPane());

    getToolbar().addSearchCommand(e -> Log.p("Todo"));
    getToolbar().addCommandToOverflowMenu("Backup Notes", null, e -> Log.p("Todo"));
    getToolbar().addCommandToOverflowMenu("Restore Notes", null, e -> Log.p("Todo"));
    getToolbar().addCommandToOverflowMenu("Rate App", null, e -> Log.p("Todo"));
}

It should be mostly self-explanatory and should construct the main UI.

Step 5: Run

To see what we have we can just edit the main class ( SwiftnotesCN1 ) and replace this code:

Form hi = new Form("Hi World");
hi.addComponent(new Label("Hi World"));
hi.show();

With this:

new ActivityMain(theme).show();

The end result still needs styling which we will do in the next step.

Before styling the result Figure 6. Before styling the result

Next Time

In the final part of this series, we will finish the app and make it look very close to its native counterpart. 

Android (robot) app Codename One

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • When Scrum Feels Like Dressing for Dinner
  • A Brief Overview of the Spring Cloud Framework
  • Hackerman [Comic]
  • AWS Cloud Migration: Best Practices and Pitfalls to Avoid

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: