<![CDATA[Stories by Reva Yoga Pradana on Medium]]> https://medium.com/@revoreva?source=rss-a7645444f16d------2 https://cdn-images-1.medium.com/fit/c/150/150/1*hNobOwGvkhA88x4Og8XZ6A@2x.jpeg Stories by Reva Yoga Pradana on Medium https://medium.com/@revoreva?source=rss-a7645444f16d------2 Medium Tue, 14 Apr 2026 06:04:02 GMT <![CDATA[Some Notes when Upgrading into Xcode 13]]> https://revoreva.medium.com/some-notes-when-upgrading-into-xcode-13-b7fbdf9f1dc4?source=rss-a7645444f16d------2 https://medium.com/p/b7fbdf9f1dc4 Wed, 13 Apr 2022 06:12:19 GMT 2022-04-13T06:20:49.187Z In iOS 15, there is a new property called sectionHeaderTopPadding, for defining padding above each section header. Suggestion to make it same like previous condition, use code below (source: https://stackoverflow.com/a/69298784/4392909):

New altool recently (or at least start from Xcode 13.x) is intermittently resulting timeout 1001, ref: https://developer.apple.com/forums/thread/699749.

Solution may be:

  • using altool from lower version (e.g: 12.5.1), or
  • retry the process until got succeed.

<Soon will re-update if any other problem occurs>

]]>
<![CDATA[Some essential parts when making an App]]> https://revoreva.medium.com/some-essential-parts-when-making-an-app-a9dca53e2511?source=rss-a7645444f16d------2 https://medium.com/p/a9dca53e2511 Thu, 15 Jul 2021 01:48:00 GMT 2021-07-15T07:50:52.083Z In my experiences, I’m figuring out some essential parts, that need to be developed from the beginning of the App. At least, in the first version of the App (e.g: 1.0.0), all of these features need to be ready.

1. Feature Flag / Remote Config

This is a system where we can control the appearance of our features. The best practices (in my opinion) is, we need to add flagging system into each of our features. Usually, it will be handled from their entry point.

So for example, there is button that shown in our homepage. This button, when clicked, it will redirecting user into feature A.
We can give flagging for the appearance of this button. Or also, we can always showing the button, but when it clicked, and if the flag is currently OFF, we can show an alert, something like “sorry, this feature is currently disabled”.
Sample Dashboard.

Usually, we’re flagging a feature, and remotely control it appearance, to handle some cases, like:

  • When the feature accidentally having a problems, we can turn it OFF
  • When the feature is ready on the App side, but the Backend / APIs is not yet ready, so we can turn it OFF, and then when the backend is ready, we can turn it ON.
  • When both App and Backend side was ready, but it still waiting for the legal / compliance things, like waiting the agreement to be ready, or the feature is still pending verification by the government. After the compliance is done, we can turn it ON.

There are many tools to supporting this system. The most popular ones (afaik) is Firebase Remote Config. It is free (afaik), and we can handle the flag to be having other values rather than Boolean. Also, we can filter the flag, to be ready on specific build number / version, only for specific platform, or only for some specific device. But, it lack of filtering based on user ID / segments (CMIIW).

Other tools that supporting based on user ID / segments is Leanplum, using service Leanplum Variables.

Or, we can have our system, end to end, from Back End to Front End. And we can customize it based on our need.

2. Handling force update

Force update means, stopping the user journey, when they use certain version. It’s important to handle this things. Usually, we need to do this when some specific versions are too old, or it contains major bugs that can’t be solved by backward compatibility from Back End side. Another reasons may be, we need to do stability on Back End or Front End side, and we need to have minimum versions for our users (so their journey will not blocked).

Usually, force update handled by, Back End checking the app version that used by the user. When it includes in list of App that need to be updated, they will returning status code 410 from many APIs. Then, when the App got that in any APIs, they will show popup or alert to users for updating their App.

Sample Alert when getting Force Update

3. Handling Force Logout

Sometimes, we need to force user to logout, when uncertain conditions is happen, like token expired for unknown reason, or uncertain bug occurred. It’s not a good journey for them, but better to prepare it on our App, as soon as possible.

Sample Alert when getting Force Logout

Usually, when we want to force user to be logout, in a certain conditions (that already set in our system), Back End will return status code 401 in all APIs, and then App detecting that, and user will be logged off.

4. Giving many fundamental values on the request headers of the request APIs

There are some attributes that need to be sent from App, to identifying current session in user. Some of them are:

  • OS Name: for collecting Data, to determine / analyze some patterns
  • OS Version: for collecting Data, to determine / analyze some patterns
  • Device Model / Type: for collecting Data, to determine / analyze some patterns
  • App Version: for collecting Data, to determine / analyze some patterns. Also usually used by parameters of force update
  • Authorization: for the credential of the users

5. Monitoring Request Logger

Usually it can be handled by Back End side. So the flow will be, whether Back End returning or receiving API response from App, they will record it into some tools, example: Kibana, Datadog.

But sometimes, Front End can manually record it. So basically, the process would be, when App sending request or receiving response from Back End, they will record it into some tools, like tools above.

Then we can creating dashboard or just querying it, for analysis many things, like uncertain response from Back End, or uncertain parameters values from Front End (combine with some Data that already sent by the App, e.g: OS Version and Device Model).

Sample Dashboard for Monitoring Request Logger

In my opinion, better to handled it by Backend side, so we can easily customize it sometimes, and it always be backward compatible.

6. Monitoring Crash Performance

Many tools are supporting this. The most popular one (I think?) is Firebase Crashlytics. The purpose is quite simple and obvious, to determine whether a crash is happen on our App, and then we can know what part that triggering it. Usually it also come with many useful data, like OS version, app version, user ID, file and line of the code that triggering the crash, and report time.

Sample Report when a Crash occured

I think that’s all that I can tell. There’s still many things that I think every App need to have, like Tracker Event (for analyzing user journey), having design system, and many more. But I think that it can comes in the middle of App Release journey / doesn’t need to be developed from the beginning.

]]>
<![CDATA[Impact of iOS 14.5]]> https://revoreva.medium.com/impact-of-ios-14-5-16a536c65910?source=rss-a7645444f16d------2 https://medium.com/p/16a536c65910 Sat, 03 Jul 2021 01:05:52 GMT 2021-07-03T01:08:26.747Z When iOS 14.5 released, all of us (iOS Engineers) may already know about update of App Tracking Transparency. Yes, from next time, all of app that tracking their users, may need to implement that consent, if not, the App may got rejected.

But, on iOS 14.5, our team also facing an UI Bug that only happened on iOS 14.5. The bug is like this:

So basically on this page, we were creating a custom UIAlertController, then we modify the constraint that on it’s child view. The parent view will be adjusted too.

And then in iOS 14.5, looks like there is an update that UIAlertController has different hierarchy of the view.

Not sure also if we previously doing it wrong tho. But after we consider that, and fix the constraint, the UI now works as expected, not only on iOS 14.5, but also on lower version of OS.

Our fixing is something like, remove the parent’s view width constraint, remake the new width constraint, and then applying it both on parent and child views. Also, we adjust the leading anchor constraint on child view based on it’s parent’s view.

Hope it help everyone who may facing it!

]]>
<![CDATA[Some notes when upgrading into XCode 12]]> https://revoreva.medium.com/some-notes-when-upgrading-into-xcode-12-1db2885282a4?source=rss-a7645444f16d------2 https://medium.com/p/1db2885282a4 Fri, 18 Jun 2021 11:24:16 GMT 2021-06-18T11:24:16.687Z On the end of 2020, our iOS Team were migrating, from XCode 11.4.1 into XCode 12.3. Some things that we’ve found previously are like these:

]]>
<![CDATA[SSL Pinning with Alamofire, most essential part]]> https://revoreva.medium.com/ssl-pinning-with-alamofire-most-essential-part-f70e29a88c72?source=rss-a7645444f16d------2 https://medium.com/p/f70e29a88c72 Fri, 18 Jun 2021 09:39:34 GMT 2021-06-18T09:39:34.241Z I don’t want to write much in here, cause already so many articles discussing this.

But, I want to highlight the most important, basic, and essential part regarding this problem. Thanks for https://devgenes.com/posts/ssl-pinning-with-alamofire for highlighting this, I don’t look any other references / authors (yet) whose highlighting this “most and basic essential part” regarding to implementing SSL Pinning with Alamofire.

yes, this is the most essential part

So yeah, in SessionManager, you need to add the base domain, not including the https://. If you not do this, than the SSL pinning for your App will not works.

before
after
]]>
<![CDATA[Different UUID from IDFA and IDFV]]> https://revoreva.medium.com/different-uuid-from-idfa-and-idfv-68be9feb8e9b?source=rss-a7645444f16d------2 https://medium.com/p/68be9feb8e9b Fri, 18 Jun 2021 09:39:08 GMT 2021-06-18T09:39:08.469Z So I just read from the Leanplum’s document, that UUID can come from 2 sources, they are IDFA (advertisingIdentifier) and IDFV (identifierForVendor).

Basically, from what I read on https://gist.github.com/hujunfeng/6265995 (thanks hujunfeng!),

  • UUID from IDFA (ASIdentifierManager.shared().advertisingIdentifier.uuidString) will remain same for all apps in a device. The value will only changed when user does full reset on the device, or manually reset the advertising idenfifier.
  • UUID from IDFV (UIDevice.current.identifierForVendor?.uuidString) will be different for (almost) all apps in a device. I say "almost", because some apps that comes from "same prefix" of Bundle ID (e.g: com.calculator.apps, and com.calculator.apps2) will be have the same UUID IDFV. The value will changed when all of that "same prefix" Bundle ID apps are deleted / uninstalled and then reinstalled.

So that’s it. Now We know which the best for us for defining the “Device ID” of our users.

]]>
<![CDATA[Using Plist to store secret values in iOS App, and ignore it in Version Control (Git)]]> https://revoreva.medium.com/using-plist-to-store-secret-values-in-ios-app-and-ignore-it-in-version-control-git-3deda4e4837a?source=rss-a7645444f16d------2 https://medium.com/p/3deda4e4837a Wed, 16 Jun 2021 11:08:00 GMT 2021-06-16T11:08:00.385Z Previously, we have some secret values hardcoded in our App, and it’s separated in many files (not have exact place to store both of them). Also, it’s tracked on our Version Control (Git in this case). We know that it’s not secure, right?

So, we decide to find other workarounds to solve this. First, we found that we can use Environment Variables in XCode, because we can set it in our project using a script, and then the script will put the secret values based on values in environment variables that we already set in our OS (In our laptop, or in CI).

But, it turns out that it will not works as we expect, because we just realized that environment variables, is only available in our Laptop and CI, not available in our user, in their device, right? https://stackoverflow.com/questions/14214741/xcode-environment-variables-not-present-during-archive

So, we tried to found another ways, to keep it secrets. Then, we found a trick! We store our values in Plist, we ignore it in our Git, and then ditributed it manually into our team.

Then, what about in our CI? We use a hacky ways, we create a script, that will generate the Plist, based on values in Environment Variables in CI, and then run that script only in our CI, so our CI will also have that Plist!

Environment Variable for KEY monitoring_token
Environment Variable for KEY third_party_key

In our CI, we generate first the Plists, using shell script ruby generate_keys.rb, and then run script for building our XCode Projects.

So, both environment (in our Laptop and in our CI) will have that Plist file, and then the building can works successfully! :)

]]>
<![CDATA[didRegisterForRemoteNotificationsWithDeviceToken not Called]]> https://revoreva.medium.com/didregisterforremotenotificationswithdevicetoken-not-called-69e2b90b268b?source=rss-a7645444f16d------2 https://medium.com/p/69e2b90b268b Wed, 16 Jun 2021 10:48:45 GMT 2021-06-16T10:48:45.537Z In our iOS App, we often found a condition when user are not getting push token from APNS. When we researching this, it’s because of:

neither the application:didRegisterForRemoteNotificationsWithDeviceToken: method nor the application:didFailToRegisterForRemoteNotificationsWithError: method is called.

When we do some next research, we also found that

on some connections, especially Wi-Fi connection, the port of APNS (5223) may got blocked.
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW3

Because of “impossible case to handle” like that, this case may got more attention into our development process. For example, we should exclude the “mandatory push token” into our vital flow, e.g: Login Flow, or educating the users to (maybe) “Switch the internet operator for a while” when getting this condition.

To decreasing the occuring of that condition, we can do some enhancement in our code, related to registering remote push notifications. After discussing with Apple and reading the Leanplum’s documentation, we found out that we can call registerForRemoteNotifications() whenever users are accept or denying the push notifications. Although we register the remote notifications, Apple will still exclude the push notifications into our users, when they rejecting the push notification, so it’s safe to still calling this function. The example code will be like this:

So, just it. Thank you guys for reading this!

]]>
<![CDATA[Remove build phase script “[CP] Check Pods Manifest.lock”]]> https://revoreva.medium.com/remove-build-phase-script-cp-check-pods-manifest-lock-f479895754b2?source=rss-a7645444f16d------2 https://medium.com/p/f479895754b2 Wed, 16 Jun 2021 09:44:33 GMT 2021-06-16T13:50:53.441Z In our company, sometimes we found a problem that our build phase script "[CP] Check Pods Manifest.lock" got timeout in CircleCI, without clear reason.

Timeout on running script "[CP] Check Pods Manifest.lock"

Then, we decide to “remove” that script from our xcodeproject, because we think that we don't need that "extra step" to make sure our installed pods is the correct ones. We thought our current setup of Cocoapodsis already good.

Btw, this are our setup of Cocoapods, in our iOS App:

  1. Commit Podfile with declare exact version for it's library
  2. Git ignore the Podfile.lock
  3. Git ignore the folder Pods
  4. Always do pod install in the beginning (before compiling the app)
I think we’ll need that script if we’re not doing step 2 and 3.

Then, how we do it (removing the build phase script)? We do that by this script, that called in Fastlane.

You can also remove it by using Podfile, in step post_integrate, like this:

Why we need to do it via script? Because:

  • if we do it manually, the script will always appear again after pod install
  • we don’t commit the xcodeproject

And this is the result:

before script removed in xcodeproject
after script removed in xcodeproject
Our log that indicating the script was removed

Our build success compiled. Since this is still an experiment, I’ll updating this post whenever something unnecessary happened.

]]>
<![CDATA[Error “transporter” when uploading into Appstore]]> https://revoreva.medium.com/error-transporter-when-uploading-into-appstore-c7546e848f1f?source=rss-a7645444f16d------2 https://medium.com/p/c7546e848f1f Thu, 06 May 2021 14:09:36 GMT 2021-07-17T12:10:06.607Z I got this problem, when uploading my App into Appstore, through Transporter and XCode.

This error is caused by renaming the username in Laptop, and the old path is not changed (based on new username). The path still pointing into

“/Users/{OLD_USERNAME}/Library/Caches/com.apple.amp.itmstransporter/obr/2.1.0/com.fasterxml.jackson.module.jackson-module-jaxb-annotations-2.9.8.jar”,

while the new path should be

“/Users/{NEW_USERNAME}/Library/Caches/com.apple.amp.itmstransporter/obr/2.1.0/com.fasterxml.jackson.module.jackson-module-jaxb-annotations-2.9.8.jar”.

To solve this, we just need to remove /Users/{OLD_USERNAME}/Library/Caches/com.apple.amp.itmstransporter entirely. And then just try to re-archive and re-upload into Appstore. Then it will trigger creating the new transporter in the right path, and automatically pointed into the new one.

PS: Thank cleardemon, for posting this info in developer apple forum!

]]>