Skip navigation
All Places > AppStudio for ArcGIS > Blog
1 2 3 Previous Next

AppStudio for ArcGIS

68 posts

We are excited to announce that AppStudio for ArcGIS version 3.2 is now available to download! This release rolls out many exciting new features, as well as improvements to help drive your overall development productivity. Read this ArcGIS Blog to learn what’s new in AppStudio 3.2.  

 

Bug Fixes:

 

 BUG-000103663

 The AppStudio Player wizard installer has inconsistencies in the translation to German 

 ENH-000116806

 Request to clarify the document "License AppStudio Standard"

 BUG-000118306

 When clicking the Landing Page button at appstudio.arcgis.com, an error is thrown: "Unable to complete operation"

 ENH-000089681

 Overlapping translated text

 BUG-000089485

 Finished download window contains a white square (AppStudio)

 BUG-000089467

 Tooltip missing

 BUG-000091419

 Localization: AppStudio Player About page not localized

 BUG-000099446

 The following error, "Fatal Error C1060: Compiler is out of heap space" occurs when using the Cloud Make tool for Windows   (x64).

 BUG-000092191

 Upload tooltip is not localized (AppStudio)

 BUG-000092175

 AppStudio UI: unlocalized button

 BUG-000087207

 MOR_I18N: AppPlayer - Search and Download strings contain incorrect character "%1"

 BUG-000087203

 MOR_I18N_STR: Show/Hide Details buttons are not translated

 BUG-000087200

 MOR_I18N_STR: App download prompt is not translated

 BUG-000087227

 MOR_I18N_STR: AppStudio Player: Untranslated dialogs when downloading App

 BUG-000089397

 Unable to install AppStudio for ArcGIS when the installation path contains '\con'. Error: The installation path must not contain   '\con', please specify a valid folder.

 BUG-000087467

 Add support for Enterprise SSO to AppStudio for ArcGIS app with ArcGIS Online or Portal Single Sign On

 BUG-000087285

 AppStudio for ArcGIS Player - iOS: "No matches for <search item>" string is not localized

 BUG-000105156

 Hyperlink for 'tel' and 'mailto' in Story Map Tour does not work in AppStudio for ArcGIS.

 BUG-000103575

 An ArcGIS Online named user is required to access AppStudio for ArcGIS downloads. This may prevent users from getting   AppStudio for ArcGIS in organizations only utilizing Portal for ArcGIS.

 BUG-000103386

 The Cancel button is not translated in the AppStudio for ArcGIS app.

 BUG-000106457

 The overview of the application in AppStudio for ArcGIS is not translated to German on a German operating system.

 BUG-000115064

 The Quick Report template in AppStudio for ArcGIS (Desktop Edition) is unable to add video attachments in Android devices.

 BUG-000111490

 The default values of the coded domain in the hosted features service is not submitted using Quick Reporter template of the   AppStudio Dev Edition Desktop Version 2.1.19

 ENH-000107824

 Customer would like to make us aware that AppStudio application DLLs do not support several security mechanisms.

 BUG-000101164

 MOR_LOC_ALL: Untranslated "Content" tab in Settings of AppStudio for ArcGIS Desktop.

 BUG-000101055

 MOR_LOC_HE: Incorrectly placed parenthesis bracket in AppStudio Make tool of AppStudio for ArcGIS Desktop on Hebrew   Mac OSX.

The goal of AppStudio is to bring native app creation tools to all ArcGIS users. As you know AppStudio provides productivity tools for building, testing, and distributing apps that can be used by both developer and non-developers...and everyone in-between.  If you peel back the technical layers of the AppStudio stack you will find various components such as the Qt SDK, Android SDK, Apple Xcode and ArcGIS Runtime that enable things like cross platform development and geospatial mapping tools.  These components are development projects in themselves, each with release timelines and feature updates. This blog post is to update you on some the current state of AppStudio versions and upcoming important dates and dependencies for different platforms.

 

AppStudio for ArcGIS 2.1 Deprecation and ArcGIS Runtime 10.2.6 Retirement

The ArcGIS Runtime is the core mapping component that gives AppStudio access to various mapping and geospatial capabilities. The initial 1.0 release of AppStudio was built on earlier 10.2.x version of the ArcGIS Runtime, and at AppStudio 2.0 we included support for both the 10.2.x Runtime as well as introduced the new 100.x Runtime.  In April of 2018 AppStudio 3.0 was released and the 10.2.x Runtime was removed completely form the AppStudio product.

The 10.2.6 ver of ArcGIS Runtime for Qt that was included in AppStudio 2.1 is now in Mature Support. This means that it will no longer receive updates, patches, or platform testing and certification.

AppStudio for ArcGIS 2.1 has been in Mature Support since April 2018 and will be retired starting April 1 2019.

Because of the support status of ArcGIS Runtime 10.2.x and issues with submitting to app stores (see the next sections), AppStudio 2.1 is being deprecated and it is recommended that users move any current development projects to a newer version of AppStudio. The apps you have already created and/or published to the app stores will continue to work, but your ability to support and enhance these apps will be limited (see next section about Android and iOS support). The AppStudio 2.1 Desktop download has already been removed from our website, if you require access to download AppStudio Desktop 2.1 for app maintenance purpose please reach out to the AppStudio team directly at appstudio@esri.com.

 

Android API Level 26 Requirement for the Google Play Store

At the beginning of November 2018 any Android app submitted to the Google Play Store (new app or update to existing app) needs to be built to target the Android API Level 26 (Android 8.0) or higher.  The AppStudio Cloud Make servers have been upgraded to support API Level 26 Android builds if you are using AppStudio Desktop 3.0 or higher.  If you have apps built with AppStudio 2.1 earlier you will not be able to submit an apps (new or update) to the Google Play Store.

Xcode 9 / iOS 11 SDK Requirement for the Apple App Store

The Apple App Store currently requires that all new apps and updates are built with Xcode 9 (iOS 11 SDK). AppStudio 2.1 and the ArcGIS Runtime 10.2.6 are use an older verion of Xcdoe and thus are not capable of creating iOS binaries (IPA files) that meet the App Store requirement.

 

April 2019 Xcode 10.1 / iOS 12 SKD Requirement for the Apple App Store

When you request an iOS build using the AppStudio Cloud Make service your AppStudio app is compiled using Apple’s Xcode tools to create a binary (ipa) file suitable for distribution.  In March 2019 Apple Inc will require that all apps (new and updates) submitted to the Apple App Store are compiled using a XCode 10.1.  This timing of the requirement is problematic because support for XCode 10 in the Qt SDK is a recent addition and the ArcGIS Runtime for Qt is still working on support for this version of the Qt SDK.  What does this mean for the AppStudio Developers? Starting in March of 2019 you will not be able to submit AppStudio app to the Apple App Store using any version of AppStudio, including the released 3.2 version of AppStudio.  We will release a beta version of AppStudio 3.3 in the beginning of March that supports Xcode 10 so you can develop and test your apps in preparation of the final release. In April we will release AppStudio 3.3 with support for Xcode 10.1 and providing a way for you to submit apps to the Apple App Store on a released version of AppStudio.  We are providing this information so you can plan accordingly with any iOS releases that may be scheduled for March or April 2019.  If you have questions or concerns about the timeline for iOS / Xcode 10.1 support, please contact the AppStudio Team appstudio@esri.com.

 

 

Ref links

https://support.esri.com/en/Products/Developers/native-runtime-sdks/arcgis-runtime-sdk-for-qt/10-2-6#product-support

 

https://support.esri.com/en/Products/Apps/app-builders/AppStudio-for-ArcGIS/3-1#product-support

 

https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html

 

https://developer.apple.com/news/?id=05072018a

 

https://developer.apple.com/news/?id=09122018c

Introduction

 

I have some strings in my database. I would like to query them. Also, I want the results quick. Simple, use SQL LIKE and put an index on it.

 

Oh wait, that's weird, it didn't work like how I want... this blog covers the common traps with searching text strings in SQLite.

 

Scenario

 

Let's look at a sample database table. This one is representing property parcels and their very famous owners.

 

CREATE TABLE parcel
(
  owner TEXT
);

INSERT INTO parcel (owner) values ('Bill Gates');
INSERT INTO parcel (owner) values ('Steve Jobs');
INSERT INTO parcel (owner) values ('Jack Dangermond');
INSERT INTO parcel (owner) values ('Steve Wozniak');
INSERT INTO parcel (owner) values ('Tim Cook');
INSERT INTO parcel (owner) values ('Mark Zuckerberg');

 

We will be running queries on the above data, similar to:

 

SELECT * FROM parcel;

 

and, at the same time, we will be studying the query's execution plan with something similar to:

 

EXPLAIN QUERY PLAN SELECT * FROM parcel;

 

Using and optimizing LIKE

 

Once you dabble in a bit of SQL you'll quickly realize that you need to use LIKE for your string searches. For example, if we want to find all owners with names beginning with the letter J we do this:

 

SELECT *
FROM parcel
WHERE owner LIKE 'j%';
-- EXPLAIN QUERY PLAN: SCAN TABLE parcel
-- OUTPUT: {"owner":"Jack Dangermond"}

 

Here, we observe that it found the right result, i.e. Jack Dangermond, however, the query needed to do a full table scan (i.e. SCAN TABLE parcel) to find that this was the only result.

 

Let's attempt to speed this up with an index and try again:

 

CREATE INDEX ix_parcel_owner ON parcel (owner);
SELECT *
FROM parcel
WHERE owner LIKE 'j%'
-- EXPLAIN QUERY PLAN: SCAN TABLE parcel
-- OUTPUT: {"owner":"Jack Dangermond"}

 

Well, we got the right result, i.e. Jack Dangermond, but, why is it still doing a full table scan (SCAN TABLE parcel)?

 

Why didn't it use my index ix_parcel_owner?

 

The answer is SQLite, unlike other databases, implements LIKE as a case insensitive search so we got Jack Dangermond which begins with a capital J even though our search pattern was "j%" which begins with a lowercase J. The index that we created was a case sensitive index. LIKE ignored the index because it needed a case insensitive index.

 

To fix this, we try again. We create an index specific for case insensitive searches.

 

CREATE INDEX ix_parcel_owner_collate ON parcel (owner COLLATE NOCASE);
SELECT *
FROM   parcel
WHERE  owner LIKE 'j%';
-- EXPLAIN QUERY PLAN: SEARCH TABLE parcel USING COVERING INDEX ix_parcel_owner_collate (owner>? AND owner<?)
-- OUTPUT: {"owner":"Jack Dangermond"}

 

There, we did it. The result is still Jack Dangermond, this time the index was used (SEARCH TABLE parcel USING COVERING INDEX ix_parcel_owner_collate). Take home message, COLLATE NOCASE is your friend.

 

Alternatives to LIKE for string contains searches

 

Now that we've got some success with LIKE, let's use it to find more things. Let's see if we can find all owners with the letter C anywhere in their name:

 

SELECT *
FROM parcel
WHERE owner LIKE '%c%';
-- EXPLAIN QUERY PLAN: SCAN TABLE parcel
-- OUTPUT: {"owner":"Jack Dangermond"}
-- OUTPUT: {"owner":"Tim Cook"}
-- OUTPUT: {"owner":"Mark Zuckerberg"}

 

Okay, we got the results we wanted. Jack Dangermond, Tim Cook and Mark Zuckerberg all have the letter C is their names. However, why are we back at full table scans (SCAN TABLE parcel)? Why isn't the index (ix_parcel_owner_collate) being used any more? That's because the B-Tree index being used works like how you look up names in a phone book. It works great if you have the starting letter(s) (i.e. divide the book in half, choose the half your letter is in, divide the book in half again).

 

However, because we don't have a starting letter, we can no longer use the phone book trick. We're back scanning every record in the table. The index we created is useless for this type of query.

 

So, what can we do? Well, there's a technique you can use but it requires rewriting the query, have a look at the following:

 

SELECT *, INSTR(LOWER(owner), LOWER('c')) idx
FROM parcel;
-- EXPLAIN QUERY PLAN: SCAN TABLE parcel
-- OUTPUT: {"idx":0,"owner":"Bill Gates"}
-- OUTPUT: {"idx":0,"owner":"Steve Jobs"}
-- OUTPUT: {"idx":3,"owner":"Jack Dangermond"}
-- OUTPUT: {"idx":0,"owner":"Steve Wozniak"}
-- OUTPUT: {"idx":5,"owner":"Tim Cook"}
-- OUTPUT: {"idx":8,"owner":"Mark Zuckerberg"}

SELECT *
FROM parcel
WHERE INSTR(LOWER(owner), LOWER('c')) > 0;
-- EXPLAIN QUERY PLAN: SCAN TABLE parcel
-- OUTPUT: {"owner":"Jack Dangermond"}
-- OUTPUT: {"owner":"Tim Cook"}
-- OUTPUT: {"owner":"Mark Zuckerberg"}

 

What is happening is we're using a function INSTR which returns the position of a substring (i.e. the letter C) in a string (i.e. owner). If the substring doesn't exist, you will simply get 0. We use the LOWER function on both the letter C and the owner to make it a case insensitive search.

 

The result is still the same as the previous version involving LIKE, i.e. we are getting all owners with the letter C in their names. However, the query plan is still doing a full table scan (SCAN TABLE parcel).

 

So, what's the point?

 

Well, SQLite allows you to index expressions! Think of it like a pre-calculated column.

 

CREATE INDEX ix_parcel_owner_instr_c ON parcel (INSTR(LOWER(owner), LOWER('c')));

 

The above statement will create an index. It may take some time. For example, if you had over 200000 records, that index may take several seconds to create. Consider that to be a good thing. Time spent here means the INSTR expression is being calculated for all records in the database once and only once. Every time we add a new record or modify an existing record, it will be the only time when that INSTR expression is calculated / recalculated.

 

That expression will never be recalculated at the time of the query. The query would just reuse the pre-calculated value that was stored in the index:

 

 

SELECT *
FROM parcel
WHERE INSTR(LOWER(owner), LOWER('c')) > 0;
-- EXPLAIN QUERY PLAN: SEARCH TABLE parcel USING INDEX ix_parcel_owner_instr_c (<expr>>?)
-- OUTPUT: {"owner":"Jack Dangermond"}
-- OUTPUT: {"owner":"Tim Cook"}
-- OUTPUT: {"owner":"Mark Zuckerberg"}

 

The above confirms we are now using the index (SEARCH TABLE parcel USING INDEX ix_parcel_owner_instr_c).

 

Code Sample

 

This AppStudio code sample was used to generate all the SQL content in this blog:

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0
import ArcGIS.AppFramework.Sql 1.0

App {
    id: app
    width: 800 * AppFramework.displayScaleFactor
    height: 640 * AppFramework.displayScaleFactor

    property string logText: ""

    Flickable {
        id: flickable

        anchors.fill: parent
        anchors.margins: 10

        contentWidth: textArea.width
        contentHeight: textArea.height
        clip: true

        TextArea {
            id: textArea

            width: flickable.width
            wrapMode: Text.WrapAtWordBoundaryOrAnywhere
            selectByMouse: true
            text: logText
        }
    }

    SqlDatabase {
        id: db
        databaseName: ":memory:"
    }

    Component.onCompleted: {
        db.open();
        exec( [
            "CREATE TABLE parcel",
            "(",
            "    owner TEXT",
            ");"
            ].join("\n") );
        exec("INSERT INTO parcel (owner) values ('Bill Gates');");
        exec("INSERT INTO parcel (owner) values ('Steve Jobs');");
        exec("INSERT INTO parcel (owner) values ('Jack Dangermond');");
        exec("INSERT INTO parcel (owner) values ('Steve Wozniak');");
        exec("INSERT INTO parcel (owner) values ('Tim Cook');");
        exec("INSERT INTO parcel (owner) values ('Mark Zuckerberg');");
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE owner LIKE 'j%';"
            ].join("\n") );
        exec("CREATE INDEX ix_parcel_owner ON parcel (owner);");
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE owner LIKE 'j%';"
            ].join("\n") );
        exec("CREATE INDEX ix_parcel_owner_collate ON parcel (owner COLLATE NOCASE);");
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE owner LIKE 'j%';"
            ].join("\n") );
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE owner LIKE '%c%';"
            ].join("\n") );
        exec( [
            "SELECT *, INSTR(LOWER(owner), LOWER('c')) idx",
            "FROM parcel;",
            ].join("\n") );
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE INSTR(LOWER(owner), LOWER('c')) > 0;"
            ].join("\n") );
        exec("CREATE INDEX ix_parcel_owner_instr_c ON parcel (INSTR(LOWER(owner), LOWER('c')));");
        exec( [
            "SELECT *",
            "FROM parcel",
            "WHERE INSTR(LOWER(owner), LOWER('c')) > 0;"
            ].join("\n") );
    }

    function exec(sql) {
        logText += "\n";
        logText += sql + "\n";

        var explain = db.query("EXPLAIN QUERY PLAN " + sql);
        if (!explain.error && explain.first()) {
            logText += "-- EXPLAIN QUERY PLAN: %1\n".arg(explain.values.detail);
            explain.finish();
        }

        var query = db.query(sql);
        if (query.error) {
            logText += query.error.databaseText;
            logText += query.error.driverText;
            logText += qsTr("NativeErrorCode: %1").arg(query.error.nativeErrorCode);
            logText += qsTr("ErrorType: %1").arg(query.error.type);
            return;
        }

        var ok = query.first();
        while (ok) {
            logText += "-- OUTPUT: %1\n".arg(JSON.stringify(query.values));
            ok = query.next();
        }
        query.finish();
    }
}

 

 

Summary

 

If speed matters to you, you cannot just create an index and just leave it there.

 

You need to check whether your queries use the index with EXPLAIN QUERY PLAN. If your index isn't being used, look at your query. Look at your WHERE clause. Think of what is happening there. Rewrite your WHERE clause if necessary. Create indexes that matches your WHERE clause.

 

If necessary, be prepared to index on expressions. Don't go overboard, we didn't create an index for every letter of the alphabet. That wasn't in our requirements today. We only wanted to search for the letter C and do that better. Over time, requirements changes. We probably will become disinterested in search for the letter C, then, feel free to drop that index. However, if a new criteria becomes more important, e.g. we want to search for all owners with Jack in the first, middle or last name, then, we will create an index to help with that purpose.

Building native apps using AppStudio for ArcGIS allows you to integrate all sorts of cool hardware with your app. The hardest part is knowing how to communicate with the hardware, and what to do with the information that you can get from (or send to) it. The following intends to be an overview of the three B's - Bluetooth, Bluetooth LE and beacons, which may help you decide which of these you might need to learn more about, to solve your hardware communication requirements.

 

Bluetooth

 

In AppStudio 3.0, we introduced support for classic Bluetooth connectivity. The most common use of classic Bluetooth for many years has been by GNSS vendors to connect their receivers to devices. You can also communicate with other sensors using Bluetooth, such as laser rangefinders and environmental sensors. The GNSS Info sample in AppStudio demonstrates how you can connect to a device with Bluetooth. To learn more about this sample see this blog.

 

Bluetooth LE

 

In AppStudio 3.1, we added beta support for Bluetooth low energy (LE). A subset of Bluetooth, as the name suggests, Bluetooth LE uses less power and is ideal for more frequent transmission of smaller amounts of data. Code samples of these are a little harder for us to offer you, as typically the devices that transmit data via Bluetooth LE, do so with proprietary information. The most prolific Bluetooth LE devices in the community are fitness devices. To use your Garmin or Fitbit device you need to connect to a proprietary app to see the information: for example, steps, distance, and calories burned. You will be able to use AppStudio's Bluetooth LE components to detect Bluetooth LE devices, but typically you wont be able to interpret the data that is transmitted. Here is a sample that demonstrates connecting to a fitness device. You may not be able to use this exactly, but it shows how to get started. Once a known device is found: a known service, characteristic and descriptor is also detected by the sample.

 

Services, characteristics and descriptors are how devices package information that they want to share via Bluetooth LE. For more information (including a diagram of how these are related) see the BluetoothLEDevice page in our API Reference. Note:  We are working to add more description and samples here!

 

One of our friends, GPS-IT, have already used AppStudio's Bluetooth LE support to create an app that communicates with their very own hardware! Their platemeter device is used to measure pasture volumes and the accompanying iOS and Android apps built with AppStudio, receive the measurement values from the hardware via Bluetooth LE.

 

Beacons

 

In coming releases of AppStudio we will be adding specific support for beacons. You can consider beacons as a subset of Bluetooth LE devices. They use the same LE protocol, but make identifier information more readily available, suitable for create alerts and triggers when interacting with the beacons.

 

And because this is not complex enough, when reading about beacons, you will see two terms: iBeacon and Eddystone. In short, these are the Apple (iBeacon) and Google (Eddystone) ways of communicating with beacons, but they don't limit which device you use to communicate with the beacon. One is not necessarily better than the other, they are just different. In AppStudio we've made progress with iBeacon properties first, and will share more about our beacon support in coming blogs and releases.

 

You might be thinking: why beacons? The most common beacon use case is that of an interactive shop or gallery. Imagine entering a museum, and when you buy your ticket you are directed to launch the museum tour guide app. In the foyer area the app will show you general info about the museum. As you enter a gallery space, information about the room and the collection you are about to see, is shown (or dictated) to you. As you approach an individual object, information about that specific object is shown to you. This guided navigation can be achieved using beacons located near each object, or entrance to a space.  This is a great way for keeping propriety information on site. The user can only see or interact with the information, whilst they at your venue. Retailers also use a similar pattern to engage with a customer: as you approach an item or location in the store, targeted advertising or specials can be shared with the user.

 

Summary

 

Knowing whether to use Bluetooth or Bluetooth LE is very much dependent on the hardware you want to integrate with your app, and the hardware itself may restrict what type or amount of information you can receive from (or send to) it. We are keen to hear what Bluetooth hardware you have or would like to integrate with your AppStudio app, and look forward to expanding more on these concepts in more blogs and in our AppStudio help.

The AppStudio Framework (AppFramework) provides QML components used when creating apps in AppStudio for ArcGIS. AppFramework library of components is unique in that it has features and capabilities that are neither natively provided by the underlying Qt framework nor the ArcGIS Runtime but are necessary and commonly used for developing apps. With every release of the AppStudio, we enhance AppFramework to exploit new underlying software and hardware device features, utility functions to improve developer productivity. In this blog, we are highlighting the beta features added to the AppFramework at the AppStudio 3.1 release (September 2018). 

 

Note: These capabilities are currently in Beta. This means we are looking forward to your feedback and functionality may undergo minor changes. Please be cautious in using these beta features in your store apps. 

 

Support for Bluetooth Low Energy (BLE) devices

We have added the following new components into AppFramework Devices plugin to support communication with Bluetooth LE devices. You can now create AppStudio apps that can discover and connect to Bluetooth LE devices, discover services, and read or write characteristics for devices that support it. You can find more information on how to use these new components in this blog post.   

 

 

 

New Email Composer component

With AppStudio 3.1, we have introduced a new Inter-App Communication plugin, which includes an EmailComposer component to launch your system’s mail client with a pre-filled draft email that is ready to send, modify, delete or save as a draft.  The following code snippet demonstrates how to show a pre-filled email by clicking on a button using the EmailComposer component.   

 

import ArcGIS.AppFramework.InterAppCommunication 1.0
EmailComposer {
id: emailcomposer
to: "example@example.com"
cc: ["example2@example.com", "example3@example.com"]
bcc: "example4@example.com"
subject: "Feedback for " + app.info.title
body:
"Device OS:" + Qt.platform.os + AppFramework.osVersion + "<p>" +
"Device Locale:" + Qt.locale().name + "<p>" +
"App Version:" + app.info.version + "<p>" +
"AppStudio Version:" + AppFramework.version
html: true
}

Button {
id: openEmailButton
text: qsTr("Generate Email")
onClicked: {
emailcomposer.show()
}
}

 

An Email Composer sample is also available in AppStudio Desktop or Player. 

 

 

      

                                                                           Email Composer Sample App

 

 

Support for cryptographic hashes

Have you ever try to make a web service call from your native app that request to provide encrypted information in the headers or you just looking to store your information securely using the hash. We have made it easier to add these features and more to your app using the new CryptographicHash and MessageAuthenticationCode components available in the AppFramework at the 3.1 release. These components provide a way to generate cryptographic hashes or hash-based message authentication codes. We have published a Cryptographic Hash sample to show you how to use Cryptographic Hash functions and Message Authentication Codes in your AppStudio apps. You can search for it in the AppStudio Desktop or just play it in AppStudio Player Samples page. 

 

 

        

                                                                         Cryptographic Hash Sample App

 

 

New Browser View component

One of the most requested features for iOS has landed in AppStudio 3.1. We are happy to introduce a new native in-app browser component called BrowserView to bring you a full Safari web browser experience for iOS devices. Under the hood, the BrowserView is powered by SafariViewController for iOS and AppFramework WebView on other platforms.  The following code sample demonstrates how to use the BrowserView component.

 

import ArcGIS.AppFramework.WebView 1.0
Button {
text: "Open BrowserView"
onClicked: {
browserView.show()
}
}

BrowserView {
id: browserView
anchors.fill: parent
url: "https://appstudio.arcgis.com/"
}

 

Note: It is recommended to set that the "enableHighDpi" property under "display" to true in the appinfo.json file so that the BrowserView displays without any UI scaling issues.  

Note: The BrowserView documentation is currently not available in online documentation or bundled in Qt Creator while in beta.  Here is a quick API reference. 

Property:

url: url  

The URL of the web page that you wish to load 

Method

show ()  

Shows Web View  

 

 

A Browser View sample app is also available to you on AppStudio Desktop and Player. 

 

     

                                                                              Browser View Sample App

 

AppFramework component enhancements

   

1. Permissions ... Permissions ... Permissions ...

We have added a new checkCapability() method into the AppFramework in 3.1 to help you check if your device has granted critical permissions such as access to the device’s location, camera, microphone, or external storage. This is extremely useful if the user has denied the permission for the first time, you can prompt a warning pop-up after detecting a disabled permission using checkCapability() method. The following code snippet shows you how to check camera permission.  The rectangle will turn green if the device has access to use the camera. 

 

Rectangle {
width: 25
height: width
color : AppFramework.checkCapability(AppFramework.Camera) ? "green" : "red"
}

 

2. New isAppInstalled() method

Have you ever try to open an app from your app and wondered if the other app is available?

Starting from AppStudio 3.1, you can use the isAppInstalled() method to check if an app is installed on your device.  The input parameter is a URI Scheme (e.g. app-urlscheme://) on iOS or a Package Name (e.g com.app.package.name) on Android.

 

Note: This method is currently only implemented on iOS and Android. On all other platforms, this method returns true regardless.

3. AppFramework.systeminformation property enhancements

 AppFramework.systeminformation now returns three new parameters, “family”, “manufacture”, and “model”, to determine if a device is a phone or a tablet, which vendor creates your device, and the model of your device. You can find how to use this property in the Screen and System Info sample, which is available in AppStudio Desktop and Player. 

 

                          

                                                                      Screen and System Info Sample App

 

 

Secure Storage Enhancements

When using Secure Storage component, previously the maximum value and key size were 214 characters on all platforms even though some platforms would allow you to store more. We have introduced two new properties to the SecureStorage component - maximumKeyLength and maximumValueLength allow you to determine the limit on the length of the key and value. With these newly introduced properties, your apps can now take full advantage of a device’s limits. In addition, secure storage is now supported on the Universal Windows Platform (UWP).

 

                   

                                                                               Secure Storage Sample App

 

 

Sharing enhancement on iOS

The Clipboard.share() method opens a sharing dialog, allowing you to share data across apps.  We have added a new option to open a URL link in Safari through this sharing dialog on iOS. 

 

    

                                                                                  Share Sheet Sample App

 

 

We hope you appreciate and use all the new beta features added in AppFramework in your own apps. Please try them out and provide any suggestions or feedback before we finalize in the next releases. Also, let us know if you are looking for any new feature that might help every AppStudio user create app faster, better, and with ease.   

 

 

 

Become an AppStudio for ArcGIS developer! Watch this video on how to sign up for a free trial.

 

Follow us on twitter @AppStudioArcGIS to keep up to date with the latest information and do not forget to let us know about your latest creations using AppStudio and be featured on the AppStudio Showcase.

Sorry, the AppStudio for ArcGIS workshop (Nov 28-29, 2018) registration is closed. If you wish to stay updated with AppStudio for ArcGIS upcoming workshops, news, and resources, please click on this link to leave your email. 

 

The AppStudio for ArcGIS team will be holding a 2-day workshop on November 28-29, 2018. This hands-on workshop will give attendees the knowledge and skills they need to quickly start building cross-platform native apps with AppStudio.


Who should attend? Esri users who are interested in building cross-platform apps using AppStudio for ArcGIS.

 

Agenda:

 

Day 1: We will introduce AppStudio for ArcGIS, its components/features, and why they’re important. You will learn to build consumer-friendly mobile apps with the AppStudio for ArcGIS templates, plus learn about AppStudio Desktop, Player, and the Cloud Make service. The day will conclude with an introduction to QML and JavaScript, the language used to create custom apps with AppStudio.

 

Day 2: Technical deep-dive into understanding AppStudio stack, building custom applications, the architecture of AppStudio and its components, e.g., ArcGIS Runtime, AppFramework, reusable components. Also, you will be exposed to user interface Material Design concepts, advanced samples, and tips and tricks to write cool apps.

 

It is recommended that you bring your own laptop (Mac or Windows) for development and a smartphone or tablet (iOS or Android) to test your apps. HTML/JavaScript or hybrid app development experience, and light reading on QML (qmlbook.org) is helpful, but not required.

 

To sum it up:


What: AppStudio 2-day Workshop
Where: Esri Campus (380 New York St, Redlands, CA 92373) or Online
When: Wednesday, Nov. 28th - Thursday, Nov. 29th
Cost: FREE

 

Registration:


Only 10 seats left! Please click this link and complete the registration form.

 

If you have any questions about the workshop, please leave a comment below.  

Kale is not food!


Kale, apparently has many health benefits such as being high in fiber and water. However, me, personally, I find it on par on eating paper and I refuse to even accept that kale is proper food!

 

Kale rant aside, this blog post is really about coding patterns for writing conditionals in an AppStudio (QML) app.

 

"Kate is not food!" app

 

I've come up with a simple app that demonstrate the conditional coding pattern.

 

It has a combo box with the values "apple", "carrot" or "kale" where. Upon a user's selection, the app will respond with the corresponding food type: "fruit", "vegetable" or "unknown" respectively.

 

To implement the above app, there are many methods I've come across, thus, I take a comparative approach covering the most common to the most peculiar.

 

Each approach has a complete working code sample and discussed.

 

Approach 1 - if statement

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0

App {
id: app

property alias food: foodComboBox.currentText
property string foodType: getFoodType(food)

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10


ComboBox {
id: foodComboBox
model: [ "apple", "carrot", "kale" ]
}

Text {
text: foodType
}
}

function getFoodType(food) {
if (food === "apple") {
return "fruit";
}
if (food === "carrot") {
return "vegetable";
}
return "unknown";
}
}

 

The above is a complete code sample that determines a type of food given a user's input.

 

We see there are two visual components, ComboBox component for the user to select "apple", "carrot" or "kale" and a Text component to display the corresponding food type "fruit", "vegetable" or "unknown" respectively.

 

The visual component is constant in all the apps shown in the blog. The only thing that differs is the implementation of the foodType property.

 

In this example, it is implemented with the if statement via the getFoodType function.

 

It's very obvious, very easy to read and maintain.


I'm usually against the if statement pattern:

  • Tends to invite over application of else and else if
  • Tends to force additional code block indentation
  • Tends to lead to unintended code paths
  • Requires repeated applications of the if statement to describe your business logic


I've carefully crafted the answer to not utilize any else statements. When using if statements, I prefer to implement early exit with return statement following the guard pattern removing one level of nesting for flatter code and helps avoids errors. See Guard (computer science) - Wikipedia 


When there are 3 or more cases if statements can become cumbersome to read and maintain. Terse cases may require a refactor moving code to their own functions.

 

Approach 2 - conditional expressions

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0

App {
id: app

property alias food: foodComboBox.currentText
property string foodType: food === "apple" ? "fruit" : food === "carrot" ? "vegetable" : "unknown"

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10

ComboBox {
id: foodComboBox
model: [ "apple", "carrot", "kale" ]
}

Text {
text: foodType
}
}
}

 

The conditional (ternary) operator is very short and deceptively simple. It is often used in 1-liner solutions.

 

I tend to use conditional for very simplest of cases.

 

As your application complexity grows, the conditional expression rapidly becomes hard to read and maintain. They tend to obfuscate what you're trying to achieve.

 

When there are 3 or more cases, it quickly loses its appeal as a 1-liner solution.

 

 

Approach 3 - switch statements

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0

App {
id: app

property alias food: foodComboBox.currentText
property string foodType: getFoodType(food)

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10

ComboBox {
id: foodComboBox
model: [ "apple", "carrot", "kale" ]
}

Text {
text: foodType
}
}

function getFoodType(food) {
switch (food) {
case "apple":
return "fruit";
case "carrot":
return "vegetable";
}
return "unknown";
}
}


The switch statement is designed to handle multiple cases. If the values for each case is concise, then, this approach works well.

 

In my apps, I find, however, as my requirement grows, the switch statement becomes longer and longer and they it ends up as code that's longer than one screenful. When that happens, we lose the conciseness of this approach. In order to get back down to something that's manageable we refactor the cases by moving the code for each cases to their own function.

 

 

Approach 4 - lookup table

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0

App {
id: app

property alias food: foodComboBox.currentText
property var foodTypes: {
"apple": "fruit",
"carrot": "vegetable"
}
property string foodType: foodTypes[food] || "unknown"

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10

ComboBox {
id: foodComboBox
model: [ "apple", "carrot", "kale" ]
}

Text {
text: foodType
}
}
}

 

This approach implements a lookup table. We leverage a Javascript object's ability to hold key value pairs. The advantages to this approach is the code is declarative with minimal imperative code.

 

I used this approach when managing large list of keys whose values are simple and defined. We simply hard code the list at the top of the app, and/or deployed the list via JSON object resource that gets loaded when the app starts.

 

This is approach is easy to read and maintain. We have a limitation that the key to the lookup table must be a string.

 

Approach 5 - invoking function by name

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0

App {
id: app

property alias food: foodComboBox.currentText
property string foodType: getFoodType(food)

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10

ComboBox {
id: foodComboBox
model: [ "apple", "carrot", "kale" ]
}

Text {
text: foodType
}
}

function getFoodType_apple() {
return "fruit";
}

function getFoodType_carrot() {
return "vegetable";
}

function getFoodType(food) {
var func = "getFoodType_" + food;
return func in app ? app[func]() : "unknown";
}
}


This approach uses the fact that we can invoke a Javascript function by name. It also requires us to use the name of the parent object (here it is called app). We have to construct the function name, and, if it exists we invoke that function.

 

I used this approach in app where the requirements were changing. I was building a conversion app. The requirements were changing, i.e. the list of inputs (e.g. the list of foods) will grow over time. This pattern was useful as it allowed me to focus on handling new cases as they occur.

 

property var bool use_merriam_webster: true

function getFoodType_tomato()
{
// A tomato is actually a fruit -- but it's a vegetable at the same time
// https://www.businessinsider.com.au/tomato-fruit-or-vegetable-2018-5?r=US&IR=T
if (use_merriam_webster) {
return "fruit";
}
return "vegetable";
}

 

Despite being the driver function being hard to read, it has advantage that it doesn't require maintenance to add new cases. We simply start coding the new cases and they will automatically be picked up.

 

Summary

 

For the "Kale is not food" app all 5 approaches shown above achieve the task and one may argue that there isn't much differences between them in achieving that task.

 

For more complex applications, some of the more obscure approaches such as lookup table or invocation by function name may become more appealing in long term ability to maintain and scale.

 

Generally, whenever I see code involving either the if or switch statement, I ask myself would it be worthwhile to check to see if another approach works better?. Usually, I find: yes, it is.

AppStudio for ArcGIS Desktop Edition provides feature-rich development tools to allow you to further configure templates, edit source code, test, distribute, and build your custom mobile or desktop apps easily and quickly. We are excited to share some of the new features and enhancements that are added to this release with you.
Upgrade ArcGIS Runtime to version 100.3
The ArcGIS Runtime API powers the mapping capabilities of AppStudio apps. With this release, we’ve upgraded ArcGIS Runtime libraries to version 100.3, which means all of the new features, enhancements, and bug fixes added to ArcGIS Runtime 100.3 are available in AppStudio 3.1, such as displaying web scenes from ArcGIS  or ArcGIS Enterprise and enhancements to scene analysis and Web Mapping Services (WMS).  
Upgrade Qt Framework to version 5.11.1 
Behind the scenes, the underlying Qt framework has been upgraded from 5.10.0 to 5.11.1, which enables you to take advantage of new functionalities, enhancements, and critical bug fixes received in Qt 5.11 and 5.11.1
Enhancements to UI
We have made a few small UI tweaks to AppStudio Desktop in this release, such as a New App button moving down to the main gallery area, and the header and side panel border width increasing. These UI updates were based on Esri’s Calcite style standard and were made to keep visual consistency across Esri’s products.  
              
                                                                                AppStudio Desktop UI
AppStudio Desktop’s Settings tool has also received a UI/UX revamp.  It's now easier than ever to use the Settings tool to navigate and find all the options and settings organized into sections.  Also as part of the redesign, the previous contents of the Advanced Settings dialog are now integrated into the Licensing, Platforms & Advanced sections.
    AppStudio Desktop Settings Tool Dialog
                                                                AppStudio Desktop Settings Tool Dialog
Enhancements to Make tool  
The Google Play Store recently changed requirements for new apps, which must target at least Android 8.0 (API level 26) to publish. AppStudio, as a cross-platform development tool, is always aware of store submission requirements for all platforms and has been taking care of this for you. We’ve updated our cloud Make servers to target Android API level 26 by default for Android apps in this release. Please check out this blog post for more details.    
 
New UI to specify app’s short name 
Your app’s title that appears under the icon on the Home screen of iOS and Android devices can now be specified, with newly introduced UI in the Settings tool’s Advanced section. This can be used to avoid a longer app title being truncated.
 
                                          AppStudio Desktop > Settings Tool > Advanced Dialog
New UI to enable background external accessories for iOS devices 
AppStudio 3.0 added support for the high accuracy GPS receivers, and introduced support for a new property, capabilities.ios.backgroundExternalAccessory, in the appinfo.json file. In this release, we have added a corresponding UI in the Settings tool Platform > iOS settings to easily help you enable or disable external accessories running in the background.    
  
                                               AppStudio Desktop > Settings Tool > Platforms > iOS Dialog
New UI to configure Windows rendering engine 
AppStudio 3.1 now supports OpenGL and ANGLE for Windows.  While adding support for two different graphics rendering engines, we’ve also introduced a new UI in the Settings tool > Platform > Windows section to allow you to choose your desired graphics rendering engine. 
 
                                AppStudio Desktop > Settings Tool > Platforms > Windows Dialog
New samples 
 We have included new samples to show newly introduced components and plugins to AppSudio AppFramework: Email Composer, Cryptographic Hash, and Browser View.  
    
                                                        Email Composer sample running in AppStudio Player
Other enhancements: 
•        New languages added: Hungarian (hu) and Catalan (ca)
•        The minimum Android version has been updated from 16 to 19
•        Gradle is now used instead of Ant for building Android apps 
•        Improved background location capture performance for Android
Bug Fixes: 

     BUG-000087200

App download prompt in AppStudio is now getting translated

     BUG-000099446

Cloud Make failing with error "Fatal Error C1060: Compiler is out of heap space" on Windows (x64) when submitting built request for a large app has been fixed.

     BUG-000101054

Misaligned strings in AppMake Summary window of AppStudio for ArcGIS Desktop on Hebrew in Mac OSX has been fixed.

     BUG-000101055

Incorrectly placed parenthesis bracket in AppStudio Make tool of AppStudio for ArcGIS Desktop on Hebrew in Mac OSX has been fixed.

     BUG-000101164

"Content" tab in Settings of AppStudio for ArcGIS Desktop now gets translated.

     BUG-000101600

Security vulnerabilities with custom URL schemes in an iOS app developed with AppStudio for ArcGIS have been resolved.

     BUG-000101979

Security vulnerability regarding system information leak with an Android application built with AppStudio for ArcGIS has been resolved.

     BUG-000103384

The 'Hide Details' and 'Show Details' buttons are now getting translated in  AppStudio for ArcGIS installer.

     BUG-000103386

The Cancel button is now getting translated in the AppStudio for ArcGIS app.

     BUG-000106457

The overview of the application in AppStudio for ArcGIS is now getting translated to German on a German operating system.

 

You can download the latest AppStudio Desktop from our website and we hope you enjoy the new features and enhancements added in this release!
Become an AppStudio for ArcGIS developer! Watch this video on how to sign up for a free trial.

Follow us on twitter @AppStudioArcGIS to keep up to date with latest information and do not forget to let us know about your latest creations using AppStudio and be featured on the AppStudio Showcase.
In order to improve the security and performance of Android apps, Google continuously updates its policies for apps published on the Google Play store. With the recent changes announced in this blog post https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html, Google has laid down a road map for the target API level requirement for Android apps.
 
Target API level requirements for Android Apps
  • From August 2018, Play store requires new apps to target Android API level 26 (Android 8.0) or higher in order to be published.
  • From November 2018, all apps, including updates to existing apps, need to target Android API level 26 (Android 8.0) or higher to be published in the Play store.
 
 
How does this impact AppStudio users? 
If you have recently tried to submit your apps to Google Play store, you might have encountered the following warning message:
 
In order to get Android apps built using AppStudio to meet the requirements of the Google Play store, we have updated our cloud Make servers to target Android API level 26 by default for Android apps. If the Play Store submission for your app has failed because of the target API level requirement, please rebuild your app using the Make tool in AppStudio and then submit it again to the Play Store. 
Please note that from August 2018, the Google Play Store only requires new apps to target Android API level 26. However, if you already have apps that are published in the Google Play Store with the target API level below Android API level 26, and plan to publish updates to them, you can still do so until the 1st of November 2018. After this date, any updates to existing apps also need to target API level 26. In this case, you will need to rebuild your app with AppStudio 3.0 or later to fulfill the requirement of the Google Play Store.
 
I hope this has been helpful in getting your Android apps to the store, and we look forward to making your experience with AppStudio better.

Summary

 

Consider a project which uses a SQLite database.

 

Over time requirements changes. We may be forced to change the schema of that SQLite database.

 

Unlike other RDBMS, SQLite doesn't allow you to add, modify or delete columns in a table after a table is created. You will be required to export the data, recreate the schema, then import the data. Such data migration exercises requires scripts to be built with attention to detail to ensure there is no data loss during data migration.

 

You can future proof your schema by storing data as JSON. AppStudio's SqlScalarFunction helps optimize the use of JSON.

 

Scenario

 

You've been tasked with creating a Geographic Quiz app.

Version 1 will ship with a set of countries and we want to quiz the user their knowledge of capitals.
Version 2 will ship with population and we want to quiz the user to rank countries in order.
Version 3 will ship with currency conversion quiz.

 

Initial App

 

The following is a sample app which is an initial implementation of Version 1. We will deconstruct this app and explore how it could handle the future requirements.

 

import QtQuick 2.7
import ArcGIS.AppFramework 1.0
import ArcGIS.AppFramework.Sql 1.0

Item {
    property FileFolder sqlFolder: FileFolder { path: "~/ArcGIS/Data/Sql" }

    ListView {
        id: listView
        anchors.fill: parent
        anchors.margins: 10
        delegate: Row { spacing: 10; Text { text: name } Text { text: capital } }
    }

    SqlDatabase {
        id: db
        databaseName: sqlFolder.filePath('countries.sqlite')
        SqlScalarFunction {
            name: 'json_value'
            method: function (json_text, key) { return json_text ? JSON.parse(json_text)[key] : null; }
        }
    }

    Component.onCompleted: {
        db.open();
        db.query("DROP TABLE IF EXISTS countries ");
        db.query("CREATE TABLE IF NOT EXISTS countries (json_text TEXT)");
        db.query("CREATE INDEX countries_name ON countries ( json_value(json_text, 'name') COLLATE NOCASE )");
        db.query("INSERT INTO countries VALUES (:json_text)", { json_text: '{"name":"United States", "capital":"Washington D.C."}'} );
        db.query("INSERT INTO countries VALUES (:json_text)", { json_text: '{"name":"Australia", "capital":"Canberra", "population": 24130000}'} );
        db.query("INSERT INTO countries VALUES (:json_text)", { json_text: '{"name":"France", "capital":"Paris"}'} );

        var sql = [
            "SELECT json_value(json_text, 'name') as name, ",
            "       json_value(json_text, 'capital') as capital ",
            "FROM   countries ",
            "WHERE  name like 'United%' "
        ].join("\n");

        listView.model = db.queryModel(sql);
    }
}

 

Schema

 

You see the schema for our app is simply:

 

CREATE TABLE countries
(
    json_text TEXT
)

 

 

 

In Version 1, we want json_text to be a JSON string with the country's name and capital defined. To preview Version 2 one of the records already has population defined as well.

 

Unpacking JSON with SqlScalarFunction

 

We have a SqlScalarFunction defined which implements:

 

 

function json_value(json_text, key)
{
    return json_text ? JSON.parse(json_text)[key] : null;
}

 

 

 

So that `SQLite` can use this to unpack a JSON string and retrieve a value by its key.

 

Indexing and Querying

 

SQLite allows one to create indexes on expressions. This means we can create an index on a key extracted from the JSON string. This feature is incredible. It means we are effectively caching an extracted value so that means we can avoid repeated calculation.

 

CREATE INDEX countries_name ON countries ( json_value(json_text, 'name') COLLATE NOCASE );

SELECT json_value(json_text, 'name') AS name,
       json_value(json_text, 'capital') AS capital
FROM   countries
WHERE  name LIKE 'United%';

 

When you check the query with `EXPLAIN QUERY PLAN` we see that it is using the index:

EXPLAIN QUERY PLAN
SELECT json_value(json_text, 'name') AS name,
       json_value(json_text, 'capital') AS capital
FROM   countries
WHERE  name LIKE 'United%';

SEARCH TABLE countries USING INDEX countries_name (<expr>>? AND <expr><?)

 

Note that a collating sequence must be specified else `LIKE` where clauses will yield a full table scan.

 

Planning

 

When planning for Versions 2 and Versions 3 of the app, you'll appreciate that we can reuse the existing SQLite database and just add or update records within. We can easily drop / create indexes to accommodate new fields and new app requirements.

We are excited to announce the release of AppStudio for ArcGIS 3.1 Beta.  Downloads are available through the Early Adopter Community and we encourage you to participate in the beta program to try out new features and enhancements, and report bugs.  Your feedback will greatly help us improve AppStudio and deliver a stable and high-performance product for everyone.  
 
Disclaimer: Do not build apps to be used in production or submit to app stores using the Beta software.

 A few of the highlights include: 

  
Desktop UI enhancements 
We have UI updates to AppStudio Desktop based on Esri’s Calcite style standard to keep visual consistency across Esri’s products.  For example, the New App button was moved down to the main gallery area, and the header and side panel border width was increased.   AppStudio Desktop’s Settings tool has also received a UI/UX revamp.  It's easier than ever to use the Settings tool to navigate and find all the options and settings organized into sections.  Also as part of redesign, the contents of Advanced Settings dialog is now available and integrated into the Licensing, Platforms & Advanced sections.
      
          
  
Upgrade ArcGIS Runtime to 100.3 
The ArcGIS Runtime version has been upgraded from 100.2.1 to 100.3, which enables you to take advantage of new functionalities, enhancements and bug fixes received in ArcGIS Runtime 100.3. 
 
Upgrade Android API level to 26
With AppStudio 3.1 beta, Android build tools have been upgraded from API level 23 to 26.
 
Enhancements for Background Location (Android)
Android 8.0 puts a restriction around background processes that it can run for at most 15 minutes since the app goes to background. We have made significant tweaks to overcome these operating system level constraints and we are excited to announce that Background Location on Android is now supported using Foreground Services. A Notification is displayed when the app enters background state and stays visible until you close the task. However, note that the OS may still decide to terminate this task if the device is under tremendous memory crunch from other apps on the device. 
 
Enhancements for Local Notification
Local Notification on Android 8.0+ now supports Notification Channels. Few optimizations went into the underlying iOS stack as well.
 
Support for Bluetooth Low Energy (BLE) devices 
We have added the following NEW components into AppFramework Devices plugin to support communication with Bluetooth LE devices. 
 
  • BluetoothLEDevice
  • BluetoothLEService
  • BluetoothLECharacteristic
  • BluetoothLEDescriptor
  • ServiceListModel
  • CharacteristicListModel
  • DescriptorListModel
 
You can now create AppStudio apps that have the ability to discover and connect to Bluetooth LE devices, discover services, and read or write characteristics for devices that support it. 
Note: If you use these in your app, you will be able to see it on your device using the new Player available via beta testing or if you build the app using cloud make of the AppStudio Desktop beta.
 
Support for cryptographic hashes
CryptographicHash and MessageAuthenticationCode components have been added to the AppStudio AppFramwork to provide a way to generate cryptographic hashes or hash-based message authentication codes, which can be used to verify the integrity of networking requests and responses. 
 
Enhancements for Position and Devices plugins
AppStudio’s 3.0 release introduced two new plug-ins, Positioning and Devices, allowing you to create an app that interacts with high - accuracy GPS receivers.  Work has continued to improve these two plugins with many performance and stability related bug fixes and enhancements, such as DeviceDiscoveryAgent crashes issue on iOS.  A new property, pairingStatus was also introduced to the SerialBluetoothDevice component, which returns the pairing status of a Bluetooth device. Notice that the GNSS Info sample app include supporting for high-accuracy GPS receivers.  You can download and check the source code through AppStudio Desktop 3.1 (Beta).   
 
Email Composer 
A new Inter-App Communication plugin has been added to AppFramework. This plugin includes the EmailComposer component, allowing you to launch an email client with a pre-filled draft email.  You can modify, delete, save, or send this draft email.  
 
Check Capability 
We have added a new checkCapability method into the AppFramework to check if your device has granted critical permissions such as Location, Storage, Camera, and Microphone. 
 
Secure Storage Enhancements
Secure Storage has introduced two new properties - maximumValueLength and maximumKeyLength, allowing you to determine the limit on the length of the key and value, with these property, your apps can now take full advantage of device limit.  Note that previously the maximum value and key size was 214 characters by default.  
 
API references of Bluetooth LE related components, CryptographicHash, MessageAuthenticationCode, Email Composer, and Check Capability are available at Qt Creator Help documentation included with the AppStudio Desktop 3.1 (Beta) install.       
  
A more comprehensive list of new features and enhancements can be found in the Early Adopter community website.  
 

Getting Started 

The beta program is open to anyone. You can join our Early Adopter Community to get access to the latest versions of AppStudio 3.1.
 
Download AppStudio Desktop 
You can download the beta version of the AppStudio Desktop 3.1 here.
 
Download AppStudio Player (iOS)
Please leave your email in this EAP thread so that we can add you to Apple’s TestFlight program to download AppStudio Player 3.1 (Beta).
 
Download AppStudio Player (Android)
AppStudio Player (Android) is available to everyone as Android open beta, you can search for AppStudio Player Beta in Google Play, or go to this link to download AppStudio Player (Android)  .
 
You are now all set to start testing the AppStudio 3.1 Beta!
 

Feedback 

Your feedback is highly appreciated and will help us to improve the final release of AppStudio for ArcGIS 3.1. For bugs and any issues you may find, please submit a bug report. You can also join the beta forum to provide feedback.     
 

Beyond Beta 

The final release is scheduled for late August. Here are a few features and enhancements we are currently working on that might be available in the 3.1 final.  
AppStudio Player for ArcGIS redesign 
We brought a brand-new look for AppStudio Desktop last year in our 2.0 release, and now, it’s time for Player.  We have started redesigning Player not only to match AppStudio Desktop’s style, but also to optimize your app testing workflow. Here is a sneak peek at Player’s new look.  
 
Desktop
  • Update underlying Qt framework to 5.11.1
Templates
  • Map Viewer Measure tool enhancements - display segment length results, ability to choose drawing color, new Identify mode to interact with map when using Measure tool, ability to take screenshots of measure results and send as email attachments. 
  • Map Viewer – Support for offline geosearch
  • Map Tour – Upgrade UI with new Qt Quick Controls   
  • Quick Report – Ability to add multiple feature service layers  
  • Quick Report – New Show Album option to enable or disable user choose a photo from the album on the Media page. 
  • Quick Report – Support iOS HEIC format image as attachments 
 
AppStudio AppFramework 
  • Introduce a new method to check whether the app is installed in the device 
  • Support SafariViewController in WebView2, which is part of the WebView module
  • Support SD Card to read/write data on Android 5.0+ devices
  • Minor enhancements in volume property in Text to Speech 
  • Support changing app status bar color
We want to thank you in advance for your support in testing  AppStudio for ArcGIS 3.1 (Beta) and we look forward to your feedback
Happy testing! 
AppStudio Team 

1. Introduction

 

This AppStudio blog describes how we can use the Networking component to detect for network connectivity and classify the type of network (LAN, WIFI, Mobile Data). This allows you to build apps that can react differently dependent on what type of network they're on, e.g. ask the user whether they want to download content whilst on an expensive mobile data network.

 

2. Minimal App - All Network Configurations

Let's start with a minimal app that shows all Network connections whether active or inactive:

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0
import ArcGIS.AppFramework.Networking 1.0

App {
    width: 640 * AppFramework.displayScaleFactor
    height: 480 * AppFramework.displayScaleFactor

    Flickable {
        anchors.fill: parent
        contentWidth: textArea.width
        contentHeight: textArea.height
        TextArea {
            id: textArea
            text: JSON.stringify(Networking.configurations, undefined, 2)
        }
    }
}

 

On my Windows machine, I get:

 

{
  "0": {
    "objectName": "",
    "valid": true,
    "name": "vEthernet (Internal Ethernet Port Windows Phone Emulator Internal Switch) 2",
    "identifier": "312537767",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 14
  },
  "1": {
    "objectName": "",
    "valid": true,
    "name": "vEthernet (VMware Virtual Ethernet Adapter for VMnet8 Virtual Switch)",
    "identifier": "287176532",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 14
  },
  "2": {
    "objectName": "",
    "valid": true,
    "name": "vEthernet (Default Switch)",
    "identifier": "287176527",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 14
  },
  "3": {
    "objectName": "",
    "valid": true,
    "name": "vEthernet (VMware Virtual Ethernet Adapter for VMnet1 Virtual Switch)",
    "identifier": "312537825",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 14
  },
  "4": {
    "objectName": "",
    "valid": true,
    "name": "Bluetooth Network Connection",
    "identifier": "312537798",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 2
  },
  "5": {
    "objectName": "",
    "valid": true,
    "name": "vEthernet (Intel(R) 82579LM Gigabit Network Connection Virtual Switch)",
    "identifier": "312537802",
    "bearerType": 1,
    "bearerTypeFamily": 1,
    "bearerTypeName": "Ethernet",
    "configurationType": 0,
    "connectTimeout": 30000,
    "purpose": 0,
    "roamingAvailable": false,
    "state": 14
  }
}

 

The things we observed about Networking.configurations are:

 

  1. it's an object, not an array,
  2. every connection is listed (both active and inactive)
  3. there are signals on Network.configurations so you can use it in property binding scenarios (i.e. the moment the network changes, e.g. device is put in airplane mode, your app automatically updates)

 

3. Active Network Configurations

 

In order to filter the list down quickly, we transform the object to an array, then filter the results using Array.prototype.filter:

 

import QtQuick 2.7
import QtQuick.Controls 2.1
import ArcGIS.AppFramework 1.0
import ArcGIS.AppFramework.Networking 1.0

App {
    width: 640 * AppFramework.displayScaleFactor
    height: 480 * AppFramework.displayScaleFactor

    Flickable {
        anchors.fill: parent
        contentWidth: textArea.width
        contentHeight: textArea.height
        TextArea {
            id: textArea
            text: JSON.stringify(
                toArray(Networking.configurations)
                    .filter(isConfigActive)
                    .map(summary),
            undefined, 2)
        }
    }

    function toArray(o) {
        return Object.keys(o).map(function (e) { return o[e]; } );
    }

    function isConfigActive(c) {
        return (c.state & NetworkConfiguration.StateActive) === NetworkConfiguration.StateActive;
    }

    function summary(c) {
        return {
            name: c.name,
            bearerType: c.bearerType
        };
    }
}

 

On my Windows machine, this reduces to an easier to read list:

 

[
  {
    "bearerType": 1,
    "name": "vEthernet (Internal Ethernet Port Windows Phone Emulator Internal Switch) 2"
  },
  {
    "bearerType": 1,
    "name": "vEthernet (VMware Virtual Ethernet Adapter for VMnet1 Virtual Switch)"
  },
  {
    "bearerType": 1,
    "name": "vEthernet (Default Switch)"
  },
  {
    "bearerType": 1,
    "name": "vEthernet (Intel(R) 82579LM Gigabit Network Connection Virtual Switch)"
  },
  {
    "bearerType": 1,
    "name": "vEthernet (VMware Virtual Ethernet Adapter for VMnet8 Virtual Switch)"
  }
]

 

On my Android device, when WIFI is enabled:

 

[
  {
    "bearerType": 2,
    "name": "WIFI"
  }
]

 

or, when Mobile Data is enabled:

 

[
  {
    "bearerType": 10,
    "name": "Mobile"
  }
]

 

On my iOS device, when WIFI is enabled:

 

[
  {
    "bearerType": 0,
    "name": "en0"
  },
  {
    "bearerType": 0,
    "name": "awdl0"
  },
  {
    "bearerType": 0,
    "name": "utun0"
  }
]

 

4. Determining if the Network is LAN, WIFI or MobileData

 

On Windows, Android and Linux the bearerType can be used to classify the network connection, e.g.

 

  • NetworkConfiguration.BearerEthernet
  • NetworkConfiguration.BearerWLAN
  • NetworkConfiguraiton.Bearer3G

 

Whilst on iOS and macOS, the bearerType may not be provided by the operating system resulting in NetworkConfiguration.BearerUnknown. To cover iOS and macOS, we note that the name of the configuration instead:

 

  • en0
  • awdl0
  • pdp_ip0

 

    function isConfigLAN(c) {
        if (c.bearerType === NetworkConfiguration.BearerEthernet) {
            return true;
        }

        if (Qt.platform.os === "osx") {
            return c.name === "en0";
        }

        return false;
    }
   
    function isConfigWIFI(c) {
        if (c.bearerType === NetworkConfiguration.BearerWLAN) {
            return true;
        }

        if (Qt.platform.os === "ios") {
            return c.name === "en0";
        }
       
        if (Qt.platform.os === "osx") {
            return c.name === "awdl0";
        }

        return false;
    }

    function isConfigMobileData(c) {
        switch (c.bearerType) {
        case NetworkConfiguration.Bearer2G:
        case NetworkConfiguration.BearerCDMA2000:
        case NetworkConfiguration.BearerWCDMA:
        case NetworkConfiguration.BearerHSPA:
        case NetworkConfiguration.BearerWiMAX:
        case NetworkConfiguration.BearerEVDO:
        case NetworkConfiguration.BearerLTE:
        case NetworkConfiguration.Bearer3G:
        case NetworkConfiguration.Bearer4G:
            return true;
        }

        if (Qt.platform.os === "ios") {
            return c.name === "pdp_ip0";
        }

        return false;
    }

    function isConfigActiveLAN(c) {
        return isConfigActive(c) && isConfigLAN(c);
    }

    function isConfigActiveWIFI(c) {
        return isConfigActive(c) && isConfigWIFI(c);
    }

    function isConfigActiveMobileData(c) {
        return isConfigActive(c) && isConfigMobileData(c);
    }

 

Now that we have these useful functions, we can quickly chain them together to determine whether we're on WIFI or MobileData. Because we convert the object to an array, we can make use of Array.prototype.some to quickly lookup a network configuration of a particular type:

 

    property var config: toArray(Networking.configurations)
    property bool isOnline: isLAN || isWIFI || isMobileData
    property bool isLAN: config.some(isConfigActiveLAN)
    property bool isWIFI: config.some(isConfigActiveWIFI)
    property bool isMobileData: config.some(isConfigActiveMobileData)
    property bool isMobileDataOnly: isMobileData && !isWIFI && !isLAN

 

 

5. Network Check Sample

 

The "Network Check" app is available for you to try which demonstrates all of the above points. You can find "Network Check" app in AppStudio.

 

  1. Launch AppStudio
  2. Select New App
  3. Click Search Icon
  4. Type: Network Check

 

Network Check

 

The "Network Check" source code is also avilable at arcgis-appstudio-samples GitHub.

AppStudio Player for ArcGIS allows you instantly run and test your AppStudio apps on a real device without build requirements. As of 3.0 release, we have identified two issues: 
  • Level 1 named users cannot sign into AppStudio Player 
  • Launching apps within AppStudio Player using Custom URL scheme on iOS devices is not working 
 
We believe these two issues are critical to the usage of Player and we are happy to inform you that an update is available to be downloaded on the platform of your choice.
  
The Player for your devices with the latest fixes (3.0.14) is now available at Apple App StoreGoogle Play Store, and Amazon Appstore. The desktop version (Windows, Mac, Linux) of AppStudio Player is also available and can be downloaded from http://doc.arcgis.com/en/appstudio/download/

The new GNSS Info sample, included in AppStudio 3.0 Desktop Edition, brings together the components in Qt and the AppStudio AppFramework that you can use to build an app that interacts with GNSS (Global Navigation Satellite System) receivers.

 

Common features of this type of apps are:

  • The requirement to browse and connect to a receiver
  • Display a location on a map along with metadata about that location
  • Presentation of available satellite information
  • Presentation of key quality parameters that may indicate the usefulness of the data received
  • Display a raw feed of the data coming from the receiver for troubleshooting purposes

 

Each of these features are shown in this app on separate tabs. You may choose to use one or more of these tabs in your own app, or use this app as it is, to test out your own GNSS receivers with your hardware.

 

What type of receivers can be used?

This app will connect to, and display location information from, GNSS receivers that output NMEA sentences. For examples of recievers that we have tested with see GPS receiver support—AppStudio for ArcGIS | ArcGIS .

 

Qt and the AppFramework can also read and write data to other bluetooth devices using the same components used in this app. For example, you can connect to a bluetooth printer using the same device discovery component and send data from your app to the printer for immediate printing.

 

For more information on the key components in this sample refer to:

 

Receiver detection

This app can detect receivers that are connected to your device using:

  • Bluetooth pairing – to connect to a receiver in your app you must first pair it with your device. Note that some receivers have a limit to the number of devices they can be paired to at anyone time. For example, the Eos Arrow can only pair to one device at a time, while Bad Elf devices can pair with up to 2 devices at a time. For information on pairing your reciever see Use a high-accuracy GPS receiver—AppStudio for ArcGIS | ArcGIS .
  • USB/COM connection – A GPS receiver that plugs into a computer via USB is displayed in the app as a COM port. To confirm which COM port your device is represented by, look at the list of devices connected to your computer. For example, on Windows go to Device Manager > Ports (COM & LPT).
  • TCP/UDP network connection – A TCP (Transmission Control Protocol) connection is bidirectional and has limited error handling. On the other hand, UDP (User Datagram Protocol) is one way only and has no error handling. Creation of a UDP connection requires the hostname and port of the destination machine (where you are running the app), while creation of a TCP connection requires the hostname and port of the machine providing the GNSS information to the destination machine.

 

On the device tab, press to select a device. Next time you launch the GNSS Info app, it will attempt to automatically connect to the last device used. You can always return to the device tab and change which device you connect to.

 

Location display

The location tab shows the current location on a map. If your device has network connectivity, an online basemap is used. A limited offline basemap is also available in the sample.

 

Key metadata about the current location is displayed. The app also allows the user to change the units in which latitude and longitude are displayed.

 

Use the location tab to confirm that the location reported from your hardware is the expected location.

 

 

Satellite sky plot

The skyplot tab shows both a skyplot and a table view of the satellites reported by the receiver. Be aware that some receivers have a physical display that may sometimes display different values to this page. Other receivers have their own companion app that also may show different results. These differences are mostly likely attributed to manufacturer specific parameters and the way each manufacturer presents data from the receiver.

 

The GNSS Info app displays the number of satellites in view, and the amount in use to calculate your location. There can also be satellites in view (or in use) that have no signal. This is usually a temporary response and should not affect the quality of a location displayed in an app.

 

Use the skyplot tab to ensure you have positioned yourself or your hardware in the best location to capture a suitable position value.

 

 

Quality tab

The quality tab lists common meta data available from a GNSS receiver. These are values you may choose to capture during data collection as attributes of your feature. Alternatively, you may use these to indicate the quality of the position to the user. For example, you might warn the user that accuracy values are greater than a prescribed threshold and disallow them to capture data.

 

 

Log tab

The log tab shows a stream of the sentences that are emitted from the receiver. Different receivers output different sent

ences. The presence or absence alone of sentences is useful for troubleshooting a receiver connection issue. The inspe

ction of the presence or absence of individual sentences can also aid diagnosis of unexpected parameter results. For example, latitude, longitude and altitude errors are only calculated when the GST sentence is present. Not all receivers

output the GST sentence. If the GST sentence is not available, then ‘No Data’ is reported on the quality tab for latitude, longitude and altitude error.

 

Use the pause button on this tab to study the latest sentences. Use the delete button to clear the screen to make it easier to read new sentences.

 

 

Switching between the tabs of this app will display to you the continuous stream of data reported from the connected GNSS receiver in several ways: as text, on a map, as a graphical representation, and in its rawest form. You can choose which of these best suits your own app, or use this app to evaluate what information is available to you from your own receiver.

Map Tour template is ideal when you want to present a linear, place-based narrative featuring images audios, or videos. Each "story point" in the narrative is geo-located. Your users have the option of clicking sequentially through the narrative, or they can browse by interacting with the map or using an optional thumbnail carousel. You can create a Map Tour using the Story Maps builder and then easily convert that to a beautiful native mobile application without writing any code. You can also configure your branding icons, colors, and images to your Map Tour apps. 
Thank you for the usage and providing us good feedback. Many exciting new features and UI enhancements have been added for this release.
Fully offline support  
Currently, Map Tour pictures, thumbnails, and text get cached locally by default, meaning that you are able to view them when you do not have Wi-Fi or a cellular connection.  In this release, we extend your ability to download and view Mobile Map Packages (MMPKs) that was created using the ArcGIS Publisher extension with anonymous use enabled. 
An MMPK ID needs to be set on AppStudio Desktop Settings > Properties > Gallery > Mobile Map Packages (mmpk) item ID field. Once the MMPK has been set on Desktop, the offline map will be automatically detected and trigger a pop-up to ask you to download in your Map Tour app.  You can also download the offline map by opening the top left menu on the Map Tour Gallery page, and choosing Download offline map.  The Clear cache option on the Gallery menu page removes the offline map, cached pictures, thumbnails, and text from your device. 
       
Note, You will not see Download offline map option on the Menu page if your MMPK was not created using ArcGIS ProPublisher extension with anonymous enabled. 
Upgrade ArcGIS Runtime SDK to 100.2.1
ArcGIS Runtime level has been upgraded from 100.1 to 100.2.1, which means some new features added to Runtime 100.2 and 100.2.1 are available in Map Tour, too.  For example, if your MMPK contains tile packages, it will be supported by Map Tour as well. 
Launching Map Tour at a specific page through a custom URL Scheme
One of the most required enhancements we received from you is to use custom URL Scheme launch a Map Tour at a specific page.  We have added this functionality to Map Tour template version 3.0, allowing you to launch a specific Map Tour or a Map Tour point through custom URL Scheme.  To do this:
 
Step 1:  Setting a URL Scheme for your Map Tour app in the Advanced Settings dialog. 
                          
Step 2:  Adding Custom URL Scheme to the app that you want to launch Map Tour.  The example below shows one of the ways to do so in QML.  
Qt.openUrlExternally('mymaptourapp://?appid=c50be5615f024cc482ccb88222a8719d&index=2’)   
 
  • mymaptourapp should be the app’s URL Scheme defined in step 1
  • c50be5615f024cc482ccb88222a8719d is the Story Map ID
  • 2 means you would like to open the second point in the Story Map directly  

 

 

Step 3:  If you wish to launch Map Tour app from another app built with AppStudio on iOS devices, you need to whitelist launch URL Scheme.  As of AppStudio 3.0 release, we have included a UI for setting Launch URL Schemes in the Advanced Settings dialog.  To do this, select another app> click Settings icon on the side panel > click the Advanced button and put the URL Scheme of your Map Tour in the Launch URL Schemes field.    
 
                         
 
Set default map tour points order 
Previously, the map tour points were sorted by the Default optionWith this release, we have provided a new Sort type field in the AppStudio Desktop Settings to allow you to specify the default map tour points sorting order with the choices of default, distance, or title. 
Ability to hide the Sorting button 
Map Tour template 3.0 has introduced a new Enabled tour item sorting field in the AppStudio Desktop Settings to hide Sorting button on the Map Tour app.  If you wish to hide Sorting button, start AppStudio Desktop, open Settings > Properties > Gallery > disable Enable tour item sorting button 
 
Data Usage warning
To help you manage your mobile data usage,  a warning message will be displayed when you are trying to download an MMPK using cellular data.  
Update UI to support iPhone X 
Map Tour’s layout has been updated to fill the iPhone X screen, and to not obscure rounded corners and indicators for both portrait and landscape orientation. 
 
Note: Map Tour template includes ArcGIS Runtime functionalities, please do not forget to set your ArcGIS Runtime license before deploying your app into production.  AppStudio Desktop is capable of automatically generate a free Runtime Lite license for you (Settings > Advanced Settings dialog > Set Lite license).   
                 
We hope you enjoy Map Tour template updates and if you are interested in updates to other templates, please click this link to find all the blog posts related to the 3.0 release of AppStudio for ArcGIS.