2

I am trying to change my package name under Android Studio, from generic_app to app_name.

I could use the "Refactor" tool from Android Studio, but I am trying to do this with a python script. However, when I make my search and replace, then I open my project in android studio, my package name do not change. Calls to app_name are use in my activities and fragments, but the package name remains the same.

Even after a build clean / rebuild project, some "generated" stuff are remaining with the old package name.

What exactly differs from the Refactor tool in Android Studio, and an external search and replace ?

How can I achieve this ?

Here is my python code (I started today, sorry if the code is awful, feel free to give me some advices) :

import os
import sys
import fileinput

sys.argv = [sys.argv[0], 'appName', 'package_name', '123', 'api_address']

def main():
    cls()
    print("Starting compiler...")
    if (len(sys.argv) > 4):
        print("")
        print("App name                  : {}".format(sys.argv[1]))
        print("Package name              : {}".format(sys.argv[2]))
        print("Establishment ID          : {}".format(sys.argv[3]))
        print("Establishment api address : {}".format(sys.argv[4]))
        input("\nPress any key to confirm")
        setup(sys.argv[1])
        refactor_package(sys.argv[1])
        change_app_name(sys.argv[2])
        set_establishment_id(sys.argv[3])
        set_establishment_api_address(sys.argv[4])
    else:
        print("Incorrect use.")
        print(".\\autocompiler.py app_name package_name establishment_id establishment_api_address")
    os.chdir('..')
    message = "\nPress any key to close"
    choice = input(message).upper()

def setup(app_name):
    command = ""
    if (os.name == 'nt'):
        command = "robocopy /E generic_app {}".format(app_name)
    else:
        command = "cp -rf ./generic_app {}".format(app_name)
    os.system(command) # Will copy generic_app in a new project folder
    os.chdir(app_name)  # Will go in the created directory
    command = "gradlew clean"
    os.system(command)  # Clear .build directory
    command = "gradlew cleanBuildCache"
    os.system(command)  # Clear .build cache directory

    # Refactor ; change establishment ID && API address ; build

def refactor_package(package_name):
    rootdir = os.getcwd()
    for root, subFolders, files in os.walk(rootdir):
        #print("ROOT == {}".format(root))
        for file in files:
            #print("\t\tFILE == {}".format(file))
            if (os.name == 'nt'):
                check_file(root + '\\' + file, package_name)
            else:
                check_file(root + '/' + file, package_name)
        for subFolder in subFolders:
            print("\t\tSUBFOLDER == {}".format(subFolders))

def check_file(filePath, packageName):
    if ("app\src\main\java\com\discodery\android" in filePath
        and ".git" not in filePath):
        print("OPENING FILE {}".format(filePath))
        with open(filePath, "r") as file:
            data = file.read()
            #print("---------- ORIGINAL ----------")
            #print(data)
            file = open(filePath, "w")
            file.write(data.replace("generic_app", packageName))
            #print("===== RESULT =====")
            file.close()
            file = open(filePath, "r")
            data = file.read()
            #print(data)
            file.close()
            # input("Press any key to continue")
    elif ("app\src\main\AndroidManifest.xml" in filePath):
        print("SHOULD EDIT MANIFEST")
        input("OK")
        with open(filePath, "r") as file:
            data = file.read()
            file = open(filePath, "w")
            file.write(data.replace('package="com.genericapp"', 'package="com.{}"'.format(packageName)))
            file.close()
    elif ("app\build.gradle" in filePath):
        print("SHOULD EDIT APP BUILD.GRADLE")
        input("OK")
        with open(filePath, "r") as file:
            data = file.read()
            file = open(filePath, "w")
            file.write(data.replace('applicationId "com.discodery.android.genericapp"', 'applicationId "com.discodery.android.{}"'.format(packageName)))
            file.close()

def change_app_name(app_name):
    pass

def set_establishment_id(establishment_id):
    pass

def set_establishment_api_address(api_address):
    pass

def cls():
    os.system('cls' if os.name == 'nt' else 'clear')

main()
Mathieu
  • 1,435
  • 3
  • 16
  • 35
  • `I could use the "Refactor" tool from Android Studio, but I am trying to do this with a python script. ` - why? – Egor Jan 08 '19 at 16:31
  • @Egor My employeer would like to automate the build of apps. We are using differents API on the same "template" app, and we would like to create more apps quickly when needed, for testing purposes. – Mathieu Jan 08 '19 at 16:35
  • If you want to build APKs for different brands with different API endpoints and package names, you can use the built-in Gradle configuration. Look at this question - https://stackoverflow.com/q/17057314/816416 -- Is this what you want to achieve? – Vishnu Haridas Jan 08 '19 at 19:25
  • @VishnuHaridas Thanks for your answer, it give me good ideas to do this. However, it seems there is a conflict with the google-services.json file, it contains the package_name and it has to be the same as the applicationId in the gradle file. – Mathieu Jan 09 '19 at 12:13
  • @Elynad Don't worry, here are some solutions for your json problem --- https://stackoverflow.com/a/34364376/816416 – Vishnu Haridas Jan 09 '19 at 13:00
  • Very useful indeed, but this answer does the opposite of my needs : I need to use the **same** google-services.json file for differents APK. This answer seems to use differents google-services.json files for the same APK – Mathieu Jan 09 '19 at 13:49
  • You cannot use the same google play services configuration accross different APKs. What you could do is include multiple configurations (for multiple apps) inside a single json and that would work. – shkschneider Jan 09 '19 at 14:39

1 Answers1

1

IntelliJ's Refactor option is indeed a "find & replace". It is just also more than that in the sense that it's more powerful and watch out for a lot of things. (Don't say it out loud but it can also introduce side effects.)

I would say the first step would be a find & replace, but an intelligent one. When you do refactor an argument's name, it only updates it and not the method 200 lines below that includes the same words in it.

It also looks for all usages, and that's way more powerful that just a global find & replace.

And the IDE provides an interface to opt-out some changes if conflicts arose. Etc. Read more at https://www.jetbrains.com/help/idea/tutorial-introduction-to-refactoring.html

shkschneider
  • 17,833
  • 13
  • 59
  • 112