Saturday, May 13, 2017

ios 10.3 test tip

1. If the app work in real device, but crash on ios simulator, then enable keychain share in target capability entitlement setting.

2. If the server self signed certificate is imported as email attachment, it is not accepted by iOS network connection by default. In order to trust the certificate for https connection, go to device settings->general->about->certificate trust Settings page, and be sure the installed server cert is trusted in there. 

SCP: Steps to use SAP mobile secure trial account for ios device management test

1. login your SAP Cloud Platform Cockpit using your trial account, select service App & Device Management.
2. Click Go to Admin console to open mobile secure admin portal
3. Select User->Manage Users, and edit the only user available
4. select action to edit, and change the user type from unmanaged to managed
5. Select Account->Device Setup, and then clickin iOS
6. In Apple MDM Certificate section, follow the step to download the csr request from the link, then upload to Apple site to get the certificate. Then upload it in step 3. A message box will indicate the operation succeeded.
7. Open Client App tab, to sign the ios afaria app.
  7.1 First create an explicit appid in your Apple developer portal web site, for example, com.sap.mobilesecure.me
  7.2 Create a development provision profile with the App ID and your development sign certificate, including all devices registered in apple dev portal
  7.3 Export your development signing p12 file from keychain
  7.4 Click Sign ios client button to Sign mobile Afaria client with above information
8. Create push certificate for sending push notification to Mobile Afaria
  8.1 From apple dev portal, create a push certificate for production with the same app id set in step 7.1
  8.2 download the push cert and import into keychain.
  8.3 export p12 file from keychain and click Install button to install it into mobile secure
9. from SAP Cloud Platform Cockpit using your trial account, select service App & Device Management, ang then Goto Mobile place
10. copy the url and open it from your ios mobile safari, the url should look like https://trial-i826633trial.sapmobileplace.com
11. follow the instruction to enroll the device
12. once it is done, it should start downloading Afaria app you just signed
13. You can also verify the push function by locking and unlocking the device from mobile secure device management.


Sunday, May 7, 2017

Which viewcontroller gets dismissed when calling iOS dismissViewController method

Apple document has the below information regarding the below method:
dismissViewControllerAnimated:completion: 
Dismisses the view controller that was presented modally by the view controller.

Discussion
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.

This document is quite confusing as there are three view controllers are involved in the operation.
self  (this is the current viewController receiving the method call)
self.presentedViewController
self.presentingViewController

So in different cases, which view controller is really got dismissed?

A quick testing shows the actual logic is implemented as below:
When dismissViewControllerAnimated method is called on a ViewController object, it first checks whether the current viewControlller's presentedViewController contains a valid object, if so, then just dismisses the presentedViewController and returns.

If the current ViewController's presentedViewController is nil, then it will dismiss the current viewController. Internally by forwarding the message to its presentingViewController as Apple document mentions. 

So basically, the method will dismiss self.presentedViewController. If the self.presentedViewController is nil, then it will dismiss the current viewController which receives the method call.


Friday, April 7, 2017

Understanding Android fragment

Android fragment provides a way to reuse a UI component with the related UI layout and java event handling code.

The interface of a fragment to the outside world is the java class inherited from Fragment class. So when an activity includes a fragment in its UI layout, it includes a Fragment element indicated by the fragment's java class name in its layout xml file. At run time, when the activity's UI layout is inflated, it will initialize the fragment java class, which will load the fragment's own UI layout. As a result, Fragment only exposes to outside world as a java class, and its UI element detail is hidden from the outside. In this way, the logic and UI layout are enclosed inside the fragment's internal space.

The fragment's java class is also responsible to communicate to holding activity to handle the UI event, basically, it calls getActivity() to get the holding activity, and then calls the related method defined in the Activity class.

Similarly, dynamic fragment loading will add an instance of fragment java class by fragment manager transaction, which has a parameter to indicate where the fragment ui element will be added.

There is a unique usage of dynamic fragment to retain the state of the fragment after configuration change. By default, when device rotation changes, the activity and its holding fragment will be destroyed and re-created again. However, if setRetainInstance(true) is called on the fragment object in Fragment.onCreate method, then when device rotation changes, the fragment object will not be destroyed along with the activity, so it still hold its existing state. Note although the Fragment object is not created again, and onCreate is not called as well, the onCreateView is still be called so that Fragment can update its UI layout after the device orientation change. This feature only applies to fragment created dynamically.

@Overridepublic void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  setRetainInstance(true);
}

Thursday, March 30, 2017

ios cordova CDVLaunchScreen storyboard and splash screen plugin

When creating an ios cordova project with cordova (6.5.0), the xcode project generated by
cordova create
command will include a resource file "CDVLaunchScreen.storyboard". This storyboard has a image view in it, which refers to image resource "LaunchStoryboard", however by default, there is no image resource included in image.xcassets. Besides, the CDVLaunchScreen.storyboard is not referred or used in any places in the generated xcode project.

As a result, the cordova ios project still uses the old launchImage resource to display the app starting
splash screen as shown below


Usually, this does not matter for the application. However, if running the project on ipad pro device's UIWebView, it will shows the useragent is iphone instead of ipad. To demo this issue, update index.html and index.js with below changes and then run it on ipad pro device, the screen shot shows the user agent is IPHONE

Index.html
 <body>
        <div class="app">
            <h1>Apache Cordova</h1>
            <label id="useragent"></label>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>

    </body>

Index.js
   // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');
        document.getElementById('useragent').innerHTML = navigator.userAgent;
        console.log('Received Event: ' + id);
    }



One way to workaround the usage agent issue is from the xcode project's General setting page, set "Launch Screen File" to "CDVLaunchScreen.storyboard".  Even if no image resource is available, the user agent for ipad pro will show the correct value as below


Note in the xcode project, before the "Launch Screen File" is set to "CDVLaunchScreen.storyboard", if the application is already deployed to the ipad pro device, then after the configuration change, the useragent will still show as IPHONE in the testing. The reason is cordova stores the useragent into ios UserDefault, so it will load the saved value as webView's useragent. 

In order to update the user agent after changing the "Launch Screen File" setting, the bundle version needs to be updated. In the project's General settings screen, the Identitiy Build number (CFBundleVersion in info.plist file) needs to be set to a new version to reset the saved user agent value. After the version is updated, the project will show the right ipad user agent on ipad pro device.

Cordova Splash Screen plugin
Although manually updating the xcode project setting, and assign the launch image resource for LaunchStoryboard image view is fine, the same function is also available in cordova ios splash screen plugin:
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/

Basically, in cordova config.xml, under platform ios section, you will need to add the below splash items
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
        <splash src="res/screen/ios/Default@2x~universal~anyany.png" />
        <splash src="res/screen/ios/Default@2x~universal~comany.png" />
        <splash src="res/screen/ios/Default@2x~universal~comcom.png" />
        <splash src="res/screen/ios/Default@3x~universal~anyany.png" />
        <splash src="res/screen/ios/Default@3x~universal~anycom.png" />
        <splash src="res/screen/ios/Default@3x~universal~comany.png" />
    </platform>

And then add those image resource png files into projectRoot/res/screen/ios folder, the image size should follow the below table

filename size width height
Default@2x~universal~anyany.png 2732x2732 any any
Default@2x~universal~comany.png 1278x2732 com any
Default@2x~universal~comcom.png 1334x750 com com
Default@3x~universal~anyany.png 2208x2208 any any
Default@3x~universal~anycom.png 2208x1242 any com
Default@3x~universal~comany.png 1242x2208 com any

Once the resource is added and config.xml is updated, then add the splash screen plugin into the cordova project. You will also need to run 
cordova prepare 
to make the CDVLaunchScreen.storyboard set to the "Launch Screen File" field, you can verify this is set properly by checking the xcode project's genearl settings.

With this change, the ipad pro UIWebView should show its user agent properly as ipad.

For more information, please refer to cordova splash screen pluguin at

Build jar file using java sdk 1.7 on mac for android studio library

Currently by default, java SDK 1.8 will be installed on mac for compile java code. However, a jar file compiled using java sdk 1.8 cannot be used by Android studio (2.3) as library project. The android project will build without error, but it will fail when trying to debug the app on device or simulator. Set SourceCompatiblity Setting in app's build.grade file also does not help.

One way to solve the issue is building the jar file with java sdk 1.7.

To do so, first download Java SE sdk 1.7 from oracle web site, and then install it on your mac. You do not need to first uninstall Java 1.8 from your mac, the new java 1.7 will be installed on the mac, but it will not remove or change any settings used by the current installed java sdk 1.8.

After the installation is done, you can check there should have two sub folders under
/Library/Java/JavaVirtualMachines   
One for 1.8 and one for 1.7.

Now you need a way to switch the java sdk version from terminal app to build the java source code. The easy way to do so is add the below two lines in your .bash_profile
alias setJdk7='export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)'
alias setJdk8='export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)'

After saving the change in bash_profile, then you can switch the java sdk version by typing the below command from terminal app:

setJdk7
set java sdk to 1.7

sdkJdk8
set java sdk to 1.8

With the above change, you can rebuild the jar file using jdk 1.7 and then import the jar file into the android studio, it should be able to build and run on device and simulator without problem.

Note: when adding new jar file as a module in android studio project, the settings.gradle will be updated to include the jar file. you will need manually add the new module in app's build.gradle's dependency section.

Sunday, March 26, 2017

Upgrade to Android Studio 2.3 on mac may fail to open existing or create new android projects

Just upgrade Android studio 2.3 on mac, and after that, the android studio cannot open the old android project or create new android project. Basically it only recognizes those android mobile projects as java desktop projects

The reason is somehow, during the upgrading, the android Support was disabled in android studio Preferences's Plugin settings. You will need to manually enable it from Preferences' Plugins screen, and then restart the android studio, and follow the prompt.



Hopefully the other functions in Android Studio 2.3 are not as fragile as this.