I have an app with the usual Google ad and in-app-payment stuff. It's accepted into the Play Store all right. Now I'd like to make it support both GMS and HMS at the same time (based on the availability of the appropriate services, the app can decide which platform to use). The app, with the Huawei functionality built in, works just fine while testing on my own devices.
However, as soon as Huawei's libraries are bundled with the app, the Play Store Console simply refuses it. No error message, just a red exclamation point. There's no doubt about the situation, I started to remove the Huawei-related parts one by one and as soon as the last bit was removed, the bundle was automagically accepted again.
Yes, sure, I might have made some error I'm not aware of but the situation is, well, rather suspicious. If it makes any difference, I use Flutter and I try to upload an app bundle, not APKs, as per normal these days. The HMS library that seems to make it or break it is com.huawei.hms:hwid:4.0.0.300 from the maven repo at https://developer.huawei.com/repo/.
So, am I just seeing things or not?
Update:
OK, the quest goes on.
This is quite recent news: https://support.google.com/googleplay/android-developer/answer/9934569
Any existing app that is currently using an alternative billing system
will need to remove it to comply with this update. For those apps, we
are offering an extended grace period until September 30, 2021 to make
any required changes. New apps submitted after January 20, 2021 will
need to be in compliance.
No matter what the policy says, the Play Console seems to enforce it already. And as I found by looking into the app bundle, the flavor approach is just not enough. Even with the other flavor, there will remain some packages referenced by Flutter. Maybe just the referenced names, not the actual code after tree shaking, but this is already enough for the refusal.
So, at the end of the day, I really think this question needs to be sorted out and some clear guidelines found for and by ourselves, developers, if we really want to write cross-ecosystem, single source Flutter apps. As for me, I sure want to do it.
I have finally found a kind of a workaround, not automatic, but a useable approach.
Create two subpackages inside your project. They look like normal Flutter packages but reside inside your app. Basically, create two folders, gms_support and hms_support beside your usual lib. Both are packages with the usual structure:
lib
lib\Xms_support.dart
lib\src
lib\pubspec.yaml
Put all your vendor-dependent stuff into identically structured files inside the respective lib\src folders and make sure both XXX_support.dart files export them the usual way. The implementations should use the same classes and same signatures. Each pubspec.yaml refers to its own, vendor-specific Flutter plugins required for their implementation.
Your main app pubspec.yaml contains both references:
dependencies:
...
gms_support:
path: gms_support/
hms_support:
path: hms_support/
Also, add another support.dart inside your main app:
export 'package:gms_support/gms_support.dart';
export 'package:hms_support/hms_support.dart';
Wherever you need vendor-specific behavior in your app, you import and use this support.dart file.
Then, when you have to change from one flavor to another, you always have to change three things in sync:
the flavor (see the details of your IDE)
comment out the other export in support.dart
comment out the other reference in pubspec.yaml and make a pub update
Different App store has different requirements for In-App Purchase Kit. The possible cause for the Play Store Console refusing your app is that your app integrated with other IAP Kit, and it does not meet the requirements of the app store review guide. You are advised to make your project support different app packages for different channels, to adapt different app store requirements.
Supporting Multiple Flavors
If your app needs to support multiple build types or flavors, configure the agconnect-services.json configuration file downloaded from AppGallery Connect for your app to implement the function. The agconnect-services.json file provides configuration information required by various services in your AppGalleryConnect project. Therefore, if you need to use multiple flavors to release different app versions, copy the agconnect-services.json file to the folder of each flavor and configure it.
Supporting Multiple Channels
If your project needs to support different app packages for different channels, the package name needs to vary depending on the channel. Change the package name in productFlavor in the build.gradle file under the app directory.
productFlavors {
huawei{
// Unique package name.
applicationId "com.example.demo.huawei"
resValue "string", "app_name", "Huawei"
}
amazon{
applicationId "com.example.demo.amazon"
resValue "string", "app_name", "Amazon"
}
}
The preceding sample code shows different packaging configurations for different channels, Huawei and Amazon. The package names are different for the two channels. If the same agconnect-services.json file is used for the two channels, the package name verification fails.
To support multiple channels, you need to add the agconnect-services.json file to the flavor folder of only the Huawei channel and ensure that the AppGallery Connect plug-in version in the project is 1.2.1.301 or later classpath'com.huawei.agconnect:agcp:1.2.1.301'). If the plug-in version is earlier than 1.2.1.301, upgrade it to 1.2.1.301 or later.
For more information, see docs.
Related
I am currently building an application which will allow mini-plugins to aid the use of my application. It is a lot like Slack, allowing user-contributed, custom plugins to aid the user. These plugins will be Swift classes. I will be setting up a system where users can submit their custom plugins to be hosted on a webpage. Users in my application will be able to select a few of these plugins that they need, and the application would import those plugins only, and add the classes containing the plugins to a top-level file so that everything in my application can use these plugin classes. How can I import these selected modules into my application files?
For example, if I have a variable webpageURLContainingPlugin, then is there anything that will allow me to import the class/module at that link?
Also, I wouldn't want to download all those plugins when creating my XCode project, as I feel it would take too much unnecessary space to store all of the possible plugins, whereas a user may only choose upto five of those to use.
If it is not possible to import a file from the internet containing these modules, please can you suggest a workaround to this issue?
Edit: I am not looking for a way to create the plugin architecture, and I have an idea of how I'd like to do that, my question is more about accessing Plugins hosted online on a webpage and putting it onto my top level files so I can access them. However, if there is a specific plugin architecture that I must follow to be able to do this, then please suggest it.
You can't. IAPs might be an option worth exploring.
AppStore review guidelines
2. Performance > 2.5 Software Requirements
2.5.2 Apps should be self-contained in their bundles, and may not read or write data outside the designated container area, nor may they download, install, or execute code, including other apps. Apps designed to teach, develop, or test executable code may, in limited circumstances, download code provided that such code is not used for other purposes. Such apps must make the source code provided by the Application completely viewable and editable by the user.
Our team has made a big app. This app has been a success with previous client.
Now other clients will be using this app, but with added requirements and/or different needs.
I would like to focus on making the current app into a generic Engine so that we can maintain this engine up-to-date across those different client-apps.
How should I:
Tackle this?
Bearing in mind that some viewControllers will need to reflect for new client
Changing all the graphics across the app
Any hint of how I can achieve? Been googling since long, could not arrive at a decent solution.
I already did something similar in the past, here is how we did:
part 1A: create a template project using demo assets (images has to have a default names ex:background_home.png).
part 1B: make sure that "special texts" are loaded from a plist (example:[HOME_TITLE:"your title"]) in this way you will be able to load customizable texts from a plist in the app bundle programmatically.
part 2: ask your designer to make a special design for the client respecting the name used by the developers in the code (ex:part 1A => background_home.png) or ask your designer to generate more or less 20 themes.
part 3: make a MACOS app or a script which will copy the original project and replace demo assets and plist by the correct one in the original project. You want the script to generate an xcode project as you will need to double check with your developer team that the project is properly setted-up, build and deployment is much easier when you have an xcode project. In other words, the script just take the folder of the original project your team made and replace some file inside. So you won't struggle with xcode project architecture, you just replace defaults assets. Also remember that storyboard files or pbxproj are xml so you can parse and edit them, but you might have some headache doing this, that's why I recommand you to just modify the assets in the project folder.
Then you can compile that project, configure it with the provisioning you want and deploy it to your clients. Thats what we did when we needed and it worked like a charm. Basically we made a MACOS app that the sale's force could use directly with the client. They just had to send to the developer team the generated xcode project in a zip and we were in charge of the compilation and deployment. We "developed" more than 600 products using that trick.
PROBLEMS:
- The code was fully visible in the xcode project and anybody could read and/or steal it.
- The projects were very similar to each others as they came from the same source code, only the texts and assets were differents.
WORKAROUND-SOLUTIONS:
- You can imagine implementing crypto when saving the archive of a project, in this way only authorized personal can unzip the archive containing the source code.
- You can create multiple projects and do the same process with different types of project. In this way you can change the type of a generated project according to client wishes ...
Hope this help!
I'm developing an iPhone app that can edit images. Ultimately, I want to have a small version that allows the user to simply edit their images, and a large version that allows social networking of the images. Then I'd like to develop a version of each for the iPad.
Being that this is my first foray into commercial mobile development, I'm confused about how to organize all these versions in Xcode. Obviously, there will be file reuse shared between each version. I guess my question is, how do I go about organizing these separate projects in the most efficient way so that they share files and so when I edit a particular file that is shared, the changes are made to each version of the application? Is there some kind of construct to follow in XCode?
Are there any links or literature on how to go about doing this? (was not sure the correct term to search for it).
Remember: If you find yourself repeating/duplicating something, suspect that you're doing it wrong.
Your Xcode project will have 4 targets in this scenario. The basic target layout for this setup looks like this:
A Static Library (for your shared source files)
A Resource Bundle (for your shared resources)
App-Full (Universal)
App-Lite (Universal)
The apps link to the shared static library, and copy the resource bundle.
Naturally, apps will have sources/libraries/dependencies which differ -- those go in the app target (or some other dependency).
Given your background: Plan on it taking a good amount of time (initially and as you go) and patience to figure out how these dependencies should be composed, used, and maintained.
I would suggest keeping the "lite" and "full" projects separate but within the same workspace. That way you can keep the shared files in one project and simply use a shared reference to them in the other. All changes made to the shared files from either project will affect both.
As far as iPhone/iPad versions, I would also suggest that you keep these apps completely separate but within the same workspace (so that they can share code) as well. If you look around about the suggestions for managing both apps in a single project (aka, universal app), the only real benefit is that customers can buy one app and can download it on either device and some may get upset if that isn't available to them. If your app is free, don't worry about it.
Lastly, a caveat about workspaces, you need to uniquely name your files across all projects. For example if you're working with a project that uses a MainViewController.h subclass and another project that uses a MainViewController.h subclass, you could assign or edit the wrong one by accident regardless of what project you're in, so be wary. If using unique file names is a problem, you can bypass using workspaces by simply creating an empty project to dump all of your shared code into and then add references to your standalone apps from there.
If you choose to keep various copies of your project for different functionality, it will be eventually confusing, as there are places when XCode offers you one thing instead of another. One such place is - when you open a project from location X, it will also show you your copy from location Y since you opened it last time. As a result, you are likely to commit more mistakes. Organizer is one more such place where you can make mistakes.
XCode is self-contained enough to maintain both iPhone and iPad versions. You will have two separate storyboards which can be made part of one project if you chose universal as the type of app.
As for various features, you shouldn't be maintaining separate copies of your project. Instead, recommended way is to keep all features within single project, and have app logic provide access to various features.
XCode keeps version of your build under Targets section when you click project. To maintain multiple versions through your dev cycle, use source code repository (git or svn).
I have my app with ID com.mydomain.AppName which is a paid version.
I decided to introduce free version as well, and through my code I easily add ads/remove some functionality with simple #defined/#ifdef business.
However, I do need my app ID to be different for free version. How do I do this conditionally (i.e. #ifdef FREE_VERSION ... etc.) for my app?
This question was answered in a previous post
The basic idea is that you create two targets and then either use #ifdefs or create separate files to control the content in the two targets. Creating another target is dead simple. Just right-click on your existing target and duplicate it. Give it the name that you want for the free app.
In your case, you'll probably want to have different icons for the Free and Paid game, so create two icon folders—one called Free-Icons and the other called Paid-Icons. Put them in the project folder and when importing attach them to one of the targets.
I duplicated the original Info.plist and Prefix.pch files and gave them different names but you could use the same names, just put them in different folders. You'll need to adjust the build settings for each target to reflect the new names.
You might also have less content in the free app. Just select the sounds and pictures that are only in the paid app and in the inspector mark the Target Membership as just the paid app.
You'll also need to edit your schemes as so that you can build two versions. I just finished doing this for a project that I'm working on and it took about two hours from start to finish to find everything that needed changed. I'm guessing I could add another version in about 15 minutes now that I know what I'm doing.
This way of doing things is way better than duplicating the code or swapping the content out in one code base because you can easily switch back and forth between targets to make sure everything works when you make changes.
You could achieve this by having different XCode projects - one for each type of app that rely on common code (aka library XCode project(s)). One XCode project would be for paid app, and would have different macros, setup functions. The other XCode project would be for free app. Both the apps's projects can include shared sources - which would be compiled based on macros (PAID or FREE) etc.
I was always wondering what's up with those Targets? What is it all about? What's the point of that? I never had to fiddle around with them, but obviously I can. Why should I want that, and what can I do with them? What's their purpose?
Each project can build multiple executables or libraries or call out to a makefile or shell script to build "stuff". Each one of these is a Target.
One iPhone project I have includes a separate target for each static library in my home grown SDK and a shell script target to build the Doxygen docs. Another project includes two targets, one for the app as used by general users, one for an administration & management edition.
In the first example, I need to build each library then link all the static libraries into an SDK test application, so my SDK Test App depends on all the library targets (but not the docs, since I don't need to constantly regen them.)
In the second example, the management and the general versions of the app share a considerable amount of code and resources. When I change one, I want to change them both.
The target is something like a "blueprint". It includes rules that tell the compiler what to do, which sources should be compiled, which files should be copied into the application bundle, which libraries should be linked.
If you want to make a Free-Version of your app one way to do so is to add a new target.
Of course you could just duplicate the whole project but then you had to keep those in sync if you change some code. Using a different targets makes this a lot easier.