Monday, March 19, 2018

Resign ipa file for running app created by other developers

Sometimes you will need to run an ipa file created by other developers on your device, in order to do so, you will need to resign the ipa file with your ios developer certificate and profile. The below are steps to do so by assuming the app name is my.app

1. rename ipa file to zip file and unzip it

2. in terminal app, cd into folder which contains zip file

3. run
rm -r "Payload/my.app/_CodeSignature"  
to delete current code sign signature. Assume the ipa file name is my.ipa

4. download you signing profile from apple dev website and then use it to replace the one in ipa file
cp "mynewprovisionprofile.mobileprovision" "Payload/my.app/embedded.mobileprovision"
The file name must be changed to embedded.mobileprofile

5. replace appid with your app id specified in your signing profile
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.sap.fiori.client.me" ./Payload/my.app/Info.plist
Assume the appid specified in the signing profile is "com.sap.fiori.client.me"

5. copy an entitlement file from your own xcode project that uses the same appid you will sign the ipa file. The entitlement file is in xcode derivedData folder's Build/Intermediates.noindex/YourAppName.build/Debug-iphoneos/YourAppName.app.xcent.
Copy this file to the folder containing the ipa file, and rename it to entitlements.xml for easy to use

6. if you want to update any resource files included in the original ipa, like plist file or image resource files, you can do it now.

7. Resign the content again with the new entitlement and sign cert
 /usr/bin/codesign --entitlements entitlements.xml -f -s "iPhone Developer: Haiquan Li (WV2JN948JT)" "./Payload/my.app"
you can get your signing cert name from keychain utility app

8. zip the payload folder to get the new ipa file
 zip -qr "my.resigned.ipa" Payload

The above steps can also be executed by using the below script.
#!/bin/sh
#To run the script, first copy provision profile embedd.mobileprovision and entitlement.xml to the 
#same folder as ipa file is stored
#then run the below command 
#sh ThisShellFileFullPath IPAFileFullPath OptionalNewAppID
#for example to resign the ipa using new bundle id of com.sap.fiori.client.me
#bash /Users/i826633/Documents/Jonathan/git826633/tools/IPA\ re-sign/resign.sh /Users/i826633/Documents/Bugs/359459passcode/FioriClient_release-1.11.2-Release-iphoneos.ipa com.sap.fiori.client.me
echo "ios ipa resign"
IPAFilePath="$1"
echo "IPA file path: $IPAFilePath"
  
IPAFileName=$(basename "$IPAFilePath" ".ipa")
echo "$IPAFileName"
ZipFileName=$IPAFileName".zip"
echo "$ZipFileName"
cp $IPAFilePath $ZipFileName
ZipFileFolder=$IPAFileName"zip"
echo "$ZipFileFolder"
tar xvf $ZipFileName
BundleFileName=$(ls ./Payload)
echo $BundleFileName
BundleName=$(basename "$BundleFileName" ".app")
echo $BundleName
#remove codesignature
rm -r "./Payload/""$BundleFileName""/_CodeSignature"
cp "embedded.mobileprovision" "./Payload/""$BundleFileName""/embedded.mobileprovision"

if [ "$2" ]; then
   /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $2" "./Payload/""$BundleFileName""/Info.plist"
else
   echo "No App ID needs to be changed"
fi

/usr/bin/codesign --entitlements entitlements.xml -f -s "iPhone Developer: Haiquan Li (WV2JN948JT)" "./Payload/""$BundleFileName"

zip -qr "$BundleFileName"".resigned.ipa" "./Payload"

Saturday, March 17, 2018

Include library module from external folder for android project

Usually the android library module is placed under the project root folder and can be easily reference from settings.gradle file using folder name. However, it requires some extra settings to use an library module from external folder.

Assuming we start with below folder structure which haves three android projects, each project has an app module and library module, the goal is to call method from mylib1 and mylib2 from the app module and mylib3 module in myapp3 project. Note mylib1 and mylib2 is not under the root folder of myapp3 project
myapp1
      app1
      mylib1 (mylib1 is a jar library, which contains a method calls myMethod1)
myapp2
      app2
      mylib2 (mylib2 is android aar library module, which contains a method calls myMethod2)
myapp3 
     app3
     mylib3 (Android library module)

In order to add modules from external folder, the app3's project settings.gradle file needs to be updated either with relative path or absolute path as shown below
include ':app', ':mylib3'
include ':mylib2'
    project(':mylib2').projectDir = new File('../myapp2/mylib2')
include ':mylib1'
    project(':mylib1').projectDir = new File('/Users/i826633/Documents/temp/app1/mylib1')

Once the external modules are added into the project app1, then to use the modules in app1's app module, the app1's module build.gradle needs to add the external modules in its dependencies section as below
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    compile project(path: ':mylib3')
    compile project(path: ':mylib2')
    compile project(path: ':mylib1')
}

Similarly, to call the methods in mylib1 and mylib2 from mylib3, the build.gradle of mylib3 needs to be updated to include the mylib1 and mylib2 as dependencies
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    compile project(path: ':mylib2')
    compile project(path: ':mylib1')
}

By the way, if a project includes many library modules, adding the modules one by one to another project's settings.gradle file would be too troublesome. In that case, all modules in the library project can be imported to another project by using includeBuild, which just imports all library modules included in the settings.gradle to the new project as shown below
include ':myapp1', ':mylib2'
includeBuild '/Users/i826633/Documents/temp/app1' 

When includeBuild is used, be sure the distributionUrl in project's gradle-wrapple.properties is gradle-4.5.1 or above
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip

Thursday, March 15, 2018

Understanding Android Studio project structure

Unlike xcode or visual studio, there is no workspace file or project file for Android studio project. So what consists of an android studio workspace or project?

First, android studio uses the term "project" to represents an usual workspace, and uses "module" to represent an usual project. Modules for executable apk file is called "app module", and modules for reusable libraries (aar or jar files) are called "library module". The android term will be used below.

An android studio project is any directory which contains the files of
settings.gradle
build.gradle
gradle.properties
and one or more directory for app modules and libraries modules. The above files are called project level files under android view, as they are in the project folder.

Settings.gradle
The most important file is settings.grade, which indicates which modules are include in the project,  the below sample settings.gradle shows two modules are included in the project "app" and "mylib3":
include ':app', ':mylib3'

Please refer to https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html for details of settings.gradle. By default, the module name is also the folder name under the project's folder

settings.gradle can also be used to indicate the path if a module is not a subfolder under the current project folder

build.gradle
Project level build.gradle usually indicates repository used to load the dependent libraries for both build time and runtime. As project does not contains any source files so the build.gradle does not contains any android SDK version info, or build type info

gradle.properties
gradle.properties file can be used to configure the environment settings for the build

The under each module folder, the only required file is build.gradle, which starts with either 'com.android.application' for android executable
or "com.android.library" for android library
or "java-library" for jar library
The module's build.gradle also include the information about how java source file and other dependent libraries are used by the current module.


Note, any build.gradle file can be used as a gradle script plugin by its container gradle file through "apply from".  So if a dependent library is not shown in the module's dependency section, the library may be applied from a sub gradle file "applied to" to the parent gradle file.



Thursday, March 8, 2018

SAP iOS SDK oData class structure

SAP iOS SDK has few classes and protocols related oData operation mentioned in the below links


Understanding the relationship between those classes and protocols will help to use them.

Protocol DataServiceProvider
This protocol defines the basic operations (create, delete, update entity) along with pingServer, loadMetadata method.

   Class OnlineODataProvider : DataServiceProvider
   A class implements the DataServiceProvider, OnlineODataProvider requires ServiceRoot URL and     SAPURLSession as init parameters, so it can send request to server to perform the data operation.


   Class OfflineOdataProvider : DataServiceProvider
   A class similar to OnlineODataProvider, but has methods that upload, download and clear the   
   offline database.


When mobile application handles oData content, it does not directly call the methods of OnlineODataProvider  or OfflineODataProvider, instead the application calls the method of DataService (or derived classes). The DataService class has generic parameter of DataServiceProvider type, which is used to handle the actual oData requests.

Class DataService<Provider: DataServiceProvider>
Then in the application, a derived class of DataService will call various methods (executeQuery etc) implemented by ODataProvider to manage proxy class objects (derived from EntityValue class), like Customers, Products. The DataService class manages the proxy class object through DataQuery class, which represents a standard SQL statement. To create DataService object, the constructor needs parameters to provide serviceRoot url, a urlSession to authenticate with backend, and a service name. The service name does not matter for online cases.

If offlineDataServiceProvider is used as generic parameter to create DataService, when first time calling open method, it will download the database from HCP MobileService, and once the offline database is created, calling the same method again will just open the existing database without sending any requests to server, so the open and following DataQuery methods will work even if the device is offline.

Class DataQuery
DataQuery class is used to specified a SQL query, such as what columns to be selected, what is the order or where conditions.

Note, although the client can choose either using online or offline OData provider, the SAP cloud platform mobile service does not have any difference in application configuration regardless which one is selected on client side. As long as the server provides a valid oData service, then the client can work with it.

Thursday, March 1, 2018

Understanding SAP Identity management for SAP Cloud Platform

SAP Cloud Platform can use three types of identity provider
1. SAP ID service
The identity service is managed by SAP for SAP community, and is default one for many SAP service.

2. SAP Cloud Identity Service provider
This identity service provider is similar to SAP ID service, but it is managed by the owner of this customer identity provider, it is recommended for SAP customer

3. Third party Identity provider
If a customer already has an identity provider that supports SAML2, then it can also be used by SAP Cloud Platform to authenticate the user.


User, Role, Group and Permission
SAP Cloud Platform uses User and Role to assign the different privileges to user for running the Cloud Platform applications.

To easily manage the users, the administrator can defines Group, a Group can have one or few predefined roles to its members, and administrator can assign multiple users to the group, and those users will automatically have the roles configured for the group.

In addition, Group can dynamically decide which user belongs to the group based on the user's attribution, which is not available for Role definition.

Html5 or Java application developers use permission defined in neo-app.json to decide what resource is required by which permission. Then administrator can configure which role was assigned to the specified permission.

Available users are defined in Identity provider.
Role, Group, Permission are defined in each individual SAP Cloud Platform Html5 or java application.