AppLovin / AppLovin-MAX-React-Native

MIT License
55 stars 30 forks source link

Can you please document (or fix) how the Ad Review feature is supposed to be integrated? #395

Open markwilcox opened 5 days ago

markwilcox commented 5 days ago

You have a magic Ruby script that integrates the App Review framework.

That includes a local .gitignore file in the folder with the frameworks. So the project file is updated with references to files that don't go in version control, but the standard RN build process now doesn't fetch these.

So I follow the docs, commit the changes, and now my builds fail on CI.

Am I supposed to run the magic Ruby script before every build? If so, why not integrate it properly via a separate React Native module, or even a separate Pod I could add to the Podfile?

This feels broken, and is definitely not best practice for a React Native module.

wuguishifu commented 5 days ago

+1 on this. I can't get a build to work on CI. Locally my build works, but then I can't install because I get an error "code signature not found". A magic Ruby script does not feel like the best solution, I'd much rather manually add the build phases and whatever.

thomasmso commented 5 days ago

The Ad Review component is optional. It's a native component that must be done with the Xcode project. If it's breaking your CI, you can omit it.

wuguishifu commented 5 days ago

Omitting Ad Review is a non-solution when AppLovin has no other way to disable harmful ads. I am currently dealing with an ad that is 1:30 long and then spams the user with app store deep links so it's impossible to leave the ad. This is unacceptable behavior, and without Ad Review there's no way to disable things like this afaik.

If there is a way to disable harmful ads without Ad Review then please let me know.

thomasmso commented 5 days ago

@wuguishifu - so Ad Review product is an iOS product by nature, and fundamentally is installed via the Ruby script. If you want, maybe you can provide more info about the "code signature not found" error and we can help troubleshoot?

Also, you/the user can use our Creative Debugger feature to report the ad.

wuguishifu commented 5 days ago

Thanks for the information, I have a meeting with my principal eng tomorrow and if we can't figure it out would you mind if I reached out to you? And it's great to hear that there are still ways to report the ads. Is it possible to see which ads are playing in my app without the ad review SDK?

I'm still not super clear why it has to be installed via a ruby script, plenty of other iOS products are not installed that way (this is the first I've ever encountered that is). Is it a design limitation of the SDK? It seems like it would be a much better DX if it was integrated as a pod -- like most other iOS products.

markwilcox commented 4 days ago

I think we're probably complaining in the wrong place, as the magic ruby script is inherited from the native iOS SDK, but it is absolutely not necessary (I've been doing iOS development almost as long as iPhone's have existed).

Plenty of other third party SDKs integrate binary frameworks without this.

If you really can't move away from the script, the install process as documented is still broken, because of the local .gitignore file in the folder that gets added by the script. If it's not intended to include the framework in version control (even though we don't have the source to build it from) then use the Podfile to add a script phase in Xcode that runs the script, rather than telling us to run it once manually. If end users could actually just check the framework in and use the script again when updating, then document that, and remove the .gitignore file from being added by the script.

As I understand it, the Creative Debugger only lets you report ads you've seen in the app, while Ad Review is going to cover everything all the users have seen. At any kind of scale, the former is not a substitute for the latter.

thomasmso commented 4 days ago

@wuguishifu - yeah, feel free to shoot me an email: thomas.so@applovin.com.

Indeed there are different ways to see which ads are playing in your app without the Ad Review SDK - we have APIs for that: network name and creative id.

@markwilcox is correct that Creative Debugger is only when you encounter the ad at the time of. Ad Review intercepts all ad traffic.

The Ruby script handles more than just installation of an SDK as it modifies the Xcode project, but I've initiated the team to investigate removing this step in the integration phase as its requirement might be more for legacy support.

techgerm commented 1 day ago

@thomasmso - @wuguishifu and I have managed to get our CI build to work but the app fails to install on real devices with the following error:

Colt.app/Frameworks/AppLovinQualityService.framework is missing its bundle executable.
Please check your build settings to make sure that a bundle executable is produced at the path "Colt.app/Frameworks/AppLovinQualityService.framework/AppLovinQualityService"
Screenshot 2024-11-18 at 8 54 32 PM

We're using the latest version of the script:

Screenshot 2024-11-18 at 8 57 40 PM

Our app does successfully install on an iOS simulator (Xcode 16.1 | iOS 18.1) but in general we have to target Rosetta in order to build our app and I'm not sure if perhaps the AppLovinQualityService does not support both architectures.

Screenshot 2024-11-18 at 9 00 00 PM

Have you seen this issue before or do you know what could be the problem here?

ACATTAN commented 1 day ago

Integrating Ad Review via CocoaPods for example is currently not possible, as there's no way to add build phases to a project that way, and Ad Review uses some information achieved during build time. Integrating the required phases manually would be relatively complex and involve many steps, which is why we've built the ruby script.

When using CI - you would need to run the ruby script on the CI system before running your build. Running the ruby script will fetch the missing folder and then your build should be successful.

A few tips:

  1. If you want to lock Ad Review to a specific version (e.g. on your CI system) - you could run the ruby script like so (e.g. for Ad Review v7.6.4):

ruby AppLovinQualityServiceSetup-ios.rb install -version 7.6.4

  1. The ruby script is fetching the Ad Review pod from a hidden local folder called .AppLovinQualityService located under user's home folder. The first time the script runs on a machine - it will download the latest pod (or the pod version you specifically requested) and store it in this local folder. Therefore every time you run the script on your CI system (except for the first time) - the pod will be fetched from this hidden folder and be placed under your project and not re-downloaded from the cloud. There's no action item here - it's just to assure you that running the script does not require an active internet connection on your CI system.

  2. If you currently have a failed setup, your build is failing and you're not sure what to do, I suggest the following steps:

    • Uninstall Ad Review from your project by running ruby AppLovinQualityServiceSetup-ios.rb uninstall
    • Build your app and make sure all is good without Ad Review
    • Run the ruby script (as mentioned above) to re-install Ad Review
techgerm commented 19 hours ago

@ACATTAN thanks for your tips. I've performed the steps from #3 several times and unfortunately I'm still not able to install on real devices. Have you ever seen the install error described here before?

markwilcox commented 17 hours ago

Integrating Ad Review via CocoaPods for example is currently not possible, as there's no way to add build phases to a project that way, and Ad Review uses some information achieved during build time. Integrating the required phases manually would be relatively complex and involve many steps, which is why we've built the ruby script.

Several other React Native modules insert build phases into the Xcode project via their react-native.config.js. Do you need more than a script phase? I could probably point to some heavily used examples. Off the top of my head I'm sure react-native-google-mobile-ads does this to automatically add ads config into the plist (although I wish they wouldn't - would be less error-prone to 1-time modify the plist). https://github.com/react-native-community/cli/blob/main/docs/dependencies.md

If you need more than the React Native build system can actually do, why not use this to insert a script phase that runs before all the other phases and does what the existing script does (although preferably don't download the framework again if it's a fixed version for the pod version, it'd be much better checked in so we can keep build times down)

When using CI - you would need to run the ruby script on the CI system before running your build. Running the ruby script will fetch the missing folder and then your build should be successful.

This was not documented, and it's not just CI... everyone in the team needs to run it, and re-run it on upgrades, or if they fetch a fresh clone. This is effectively a dependency that is outside of version control and existing package management solutions. That's definitely an anti-pattern.

A few tips:

  1. If you want to lock Ad Review to a specific version (e.g. on your CI system) - you could run the ruby script like so (e.g. for Ad Review v7.6.4):

ruby AppLovinQualityServiceSetup-ios.rb install -version 7.6.4

  1. The ruby script is fetching the Ad Review pod from a hidden local folder called .AppLovinQualityService located under user's home folder. The first time the script runs on a machine - it will download the latest pod (or the pod version you specifically requested) and store it in this local folder. Therefore every time you run the script on your CI system (except for the first time) - the pod will be fetched from this hidden folder and be placed under your project and not re-downloaded from the cloud. There's no action item here - it's just to assure you that running the script does not require an active internet connection on your CI system.

Almost all commercial CI systems give you a fresh VM, every time, so unless you explicitly ask it to cache a hidden folder (which we didn't know was there) then it's going to be downloading it again.

wuguishifu commented 16 hours ago

At the very minimum, an action item for the AppLovin team is to update the documentation of this script and the hidden local folder. Right now, it implies that as soon as I run ruby AppLovinQualityServiceSetup-ios.rb, I'm good to go forever. This is not the case, and leads to a poor DX when using AppLovin. Furthermore, if I'm cleaning up and no longer need AppLovin (or simply don't want old versions installed on my computer) there would be no way of knowing about this hidden local folder other than stumbling upon this issue thread. I just checked and have around half a gig of data in the .AppLovinQualityService folder, most of which is old versions that I'm not using.

Also, as a confirmation, react-native-google-mobile-ads does indeed use react-native.config.js to inject build phases as seen here:

module.exports = {
  dependency: {
    platforms: {
      android: {
        packageImportPath: 'import io.invertase.googlemobileads.ReactNativeGoogleMobileAdsPackage;',
      },
      ios: {
        scriptPhases: [
          {
            name: '[RNGoogleMobileAds] Configuration',
            path: './ios_config.sh',
            execution_position: 'after_compile',
            input_files: ['$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)'],
          },
        ],
      },
    },
  },
};