<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: iDeskangel</title>
    <description>The latest articles on DEV Community by iDeskangel (@deskangel).</description>
    <link>https://dev.to/deskangel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F608632%2F8d7fa0dd-8970-40c8-a627-0dda27790b07.png</url>
      <title>DEV Community: iDeskangel</title>
      <link>https://dev.to/deskangel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/deskangel"/>
    <language>en</language>
    <item>
      <title>How Flutter does conditional compilation</title>
      <dc:creator>iDeskangel</dc:creator>
      <pubDate>Thu, 17 Jun 2021 08:06:27 +0000</pubDate>
      <link>https://dev.to/deskangel/how-flutter-does-conditional-compilation-5a5m</link>
      <guid>https://dev.to/deskangel/how-flutter-does-conditional-compilation-5a5m</guid>
      <description>&lt;p&gt;When we are using &lt;code&gt;C/C++&lt;/code&gt;, if there are some codes needn't be compiled, all we have to do is add some conditional compilation codes ( &lt;code&gt;#ifdef #endif&lt;/code&gt;), but for &lt;code&gt;Java&lt;/code&gt;, &lt;code&gt;Kotlin&lt;/code&gt;, &lt;code&gt;Dart&lt;/code&gt;, it is hard to achieve that - not it can't be done, but the compiler doesn't support the "conditional compilation" features and in order to achieve the same results, we need do it in other ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  The reason
&lt;/h3&gt;

&lt;p&gt;It started when I wanted to distribute &lt;a href="https://play.google.com/store/apps/details?id=com.deskangel.daremote"&gt;DaRemote&lt;/a&gt; to Huawei app store. After connecting to &lt;code&gt;HMS Core&lt;/code&gt;, I found that there are some extra permissions. For example, &lt;code&gt;HMS Core&lt;/code&gt; Sdk requires &lt;code&gt;permission to install apps&lt;/code&gt;, and the app distributed to Huawei app store does not need &lt;code&gt;Google play settlement service&lt;/code&gt; permission.&lt;/p&gt;

&lt;p&gt;Therefore, it is desirable to exclude some codes and &lt;code&gt;SDKs&lt;/code&gt; and related &lt;code&gt;packages&lt;/code&gt; from the compilation environment according to different conditions.&lt;/p&gt;

&lt;p&gt;And to achieve this, it needs to be done in two parts: one for Android native side and one for Flutter/Dart side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Java &amp;amp; Kotlin implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Configure build.gradle file
&lt;/h4&gt;

&lt;p&gt;The native side for Android is compiled using &lt;code&gt;gradle&lt;/code&gt;, so the setup of "conditional compilation" is also done through the configuration of &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Gradle supports setting different flavors to achieve different compilation configurations. Previously, I just used it to modify some parameters, such as &lt;code&gt;AppId&lt;/code&gt;, &lt;code&gt;version number&lt;/code&gt;, etc. Now we want to import different SDK dependencies and specify different code through it.&lt;/p&gt;

&lt;p&gt;First, two different flavors were created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;
    &lt;span class="n"&gt;flavorDimensions&lt;/span&gt; &lt;span class="s2"&gt;"flavor_iap"&lt;/span&gt;
    &lt;span class="n"&gt;productFlavors&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dimension&lt;/span&gt; &lt;span class="s2"&gt;"flavor_iap"&lt;/span&gt;
            &lt;span class="n"&gt;signingConfig&lt;/span&gt; &lt;span class="n"&gt;signingConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;releaseGoogle&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;huawei&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dimension&lt;/span&gt; &lt;span class="s2"&gt;"favor_iap"&lt;/span&gt;
            &lt;span class="n"&gt;signingConfig&lt;/span&gt; &lt;span class="n"&gt;signingConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;releaseHuawei&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure different &lt;code&gt;sourceSets&lt;/code&gt; for them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;
    &lt;span class="n"&gt;sourceSets&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;srcDirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/google"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;huawei&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;srcDirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/huawei"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, associate the dependency with the flavor, i.e. prefix &lt;code&gt;implementation&lt;/code&gt; with the name of the flavor and use the lower camel case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"&lt;/span&gt;
    &lt;span class="n"&gt;huaweiImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.huawei.hms:appservice:5.0.4.302'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure source code
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;sourceSets&lt;/code&gt; above configures different code sets, and these specified code sets will be merged with the code under &lt;code&gt;src/main&lt;/code&gt; - &lt;strong&gt;Note that it is a merge and not a replacement&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first step is to move the code that would conflict under the original &lt;code&gt;/src/main&lt;/code&gt; to its respective flavor directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since there is only &lt;code&gt;MainActivity.kt&lt;/code&gt; file in the directory (&lt;code&gt;src/main/kotlin/com/... /...&lt;/code&gt;) in my Flutter project, just leave the folder empty after moving the file away.&lt;/p&gt;

&lt;p&gt;Also create &lt;code&gt;google/kotlin/com/... /...&lt;/code&gt;  and &lt;code&gt;huawei/kotlin/com/... /...&lt;/code&gt; directories under &lt;code&gt;src&lt;/code&gt; path, with the same structure as the original &lt;code&gt;src/main&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The second step is to create your own &lt;code&gt;MainActivity.kt&lt;/code&gt; file in each of the two directories, and then just implement your own functionality depending on the demands.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Flutter configuration
&lt;/h3&gt;

&lt;p&gt;The main principle of the implementation under Flutter is that it can specify different entry files with the following compilation parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter build apk &lt;span class="nt"&gt;--help&lt;/span&gt;
....
&lt;span class="nt"&gt;-t&lt;/span&gt;, &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;path&amp;gt; The main entry-point file of the application, as run on the
                                    device.
                                    If the &lt;span class="s2"&gt;"--target"&lt;/span&gt; option is omitted, but a file name is provided
                                    If the &lt;span class="s2"&gt;"--target"&lt;/span&gt; option is omitted, but a file name is provided on the &lt;span class="nb"&gt;command &lt;/span&gt;line, &lt;span class="k"&gt;then &lt;/span&gt;that is used instead.
                                    &lt;span class="o"&gt;(&lt;/span&gt;defaults to &lt;span class="s2"&gt;"lib/main.dart"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, it also supports specifying flavors that can be passed through to gradle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--flavor&lt;/span&gt; Build a custom app flavor as defined by platform-specific build
                                    setup.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it supports different entry files, the code needs to do some processing to separate the &lt;code&gt;main.dart&lt;/code&gt; file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code structure modification
&lt;/h4&gt;

&lt;p&gt;I renamed the original &lt;code&gt;main.dart&lt;/code&gt; to &lt;code&gt;daremote.dart&lt;/code&gt; (the name of the main widget), removed the &lt;code&gt;main&lt;/code&gt; function, and created a &lt;code&gt;main.google.dart&lt;/code&gt; file and a &lt;code&gt;main.huawei.dart&lt;/code&gt; file in the lib directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib
├── daremote.dart
├── main.google.dart
├── main.huawei.dart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  compile script
&lt;/h4&gt;

&lt;p&gt;Since there is no good way to "conditionally control" the packages listed in &lt;code&gt;pubspec.yaml&lt;/code&gt;, for example, there is no way to create an entry like &lt;code&gt;google_dependencies&lt;/code&gt;, so the only way to control it is with the command &lt;code&gt;flutter pub remove&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub remove &lt;span class="nt"&gt;--offline&lt;/span&gt; in_app_purchase
flutter build appbundle &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--flavor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;huawei &lt;span class="nt"&gt;-t&lt;/span&gt; lib/main.huawei.dart
flutter pub add &lt;span class="nt"&gt;--offline&lt;/span&gt; in_app_purchase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To compile for huawei, remove google's &lt;code&gt;in_app_purchase&lt;/code&gt; package first, then in the &lt;code&gt;flutter build&lt;/code&gt; command, specify the flavor via &lt;code&gt;--flavor&lt;/code&gt; parameter, specify the &lt;code&gt;main&lt;/code&gt; file via &lt;code&gt;-t&lt;/code&gt;, and add the package back after the compilation is completed.&lt;/p&gt;

&lt;h3&gt;
  
  
  vscode configuration
&lt;/h3&gt;

&lt;p&gt;In development, the project needs to be compiled and debugged, in vscode, we can set up vscode's &lt;code&gt;launch.json&lt;/code&gt;. The important thing to note is to configure the &lt;code&gt;program&lt;/code&gt; field to specify the entry file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"huawei"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/main.huawei.dart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"--flavor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"huawei"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"-t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"lib/main.huawei.dart"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lib/main.google.dart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"--flavor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"-t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"lib.main.google.dart"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Finally
&lt;/h3&gt;

&lt;p&gt;For interpreted languages, it's fine, but for compiled languages, it's really inconvenient not to have "conditional compilation". In order to achieve the same purpose, a lot of extra work has to be done, most notably in a piecemeal fashion.&lt;/p&gt;

&lt;p&gt;At one point, I had thought to control all processes by bash scripts, but finally took some time to study how to achieve the purpose by using the features provided by the framework itself.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>gradle</category>
      <category>android</category>
    </item>
  </channel>
</rss>
