DEV Community

David Li
David Li

Posted on • Originally published at friendlyuser.github.io on

How to upload apks to google drive in bitrise

Bitrise is a continuous integration and delivery platform that allows you to automate your build, test, and deployment processes. You can define these processes using a combination of pre-built steps and custom scripts written in Bash or Go.

Using the google drive api we can upload apks to a specified google drive folder using a service account and sharing the folder to that service account.

https://drive.google.com/drive/u/4/folders/{folderId}
Enter fullscreen mode Exit fullscreen mode

Note once the folder is shared to that service account we can upload files to google drive using the folder id. Depending on demand its possible to extend this to upload to a specific folder under the parent folder.

package main

import (
    "fmt"
    "os"

    "github.com/FriendlyUser/bitrise-step-google-drive-uploader/pkg/utils"
)

func main() {
    fmt.Println("This is the value specified for the input 'service_key_path':", os.Getenv("service_key_path"))
    // and print folder_id
    fmt.Println("This is the value specified for the input 'folder_id':", os.Getenv("folder_id"))

    serviceAccount := os.Getenv("service_key_path")
    folderId := os.Getenv("folder_id")

    // find all files with the extension ending with *.apk
    files, err := utils.FindFiles("**/*.apk")
    // check if BITRISE_APK_PATH is set
    if os.Getenv("BITRISE_APK_PATH") != "" {
        // if it is set, add it to the files slice
        files = append(files, os.Getenv("BITRISE_APK_PATH"))
    }

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // upload all apk files
    for _, file := range files {
        utils.UploadFile(serviceAccount, file, folderId)
    }

    os.Exit(0)
}
Enter fullscreen mode Exit fullscreen mode

This is a modified version of the Go program that is designed to be used as a build step in the Bitrise CI/CD platform. The program reads in two input environment variables: service_key_path and folder_id. It then uses the utils package to search for all files with the .apk extension in the current directory and its subdirectories, and adds the BITRISE_APK_PATH environment variable (if it is set) to the list of files. Finally, the program iterates over the list of files and uses the utils.UploadFile function to upload each file to Google Drive using the serviceAccount and folderId variables.

The program then exits with a status code of 0, indicating success. It is good practice to always specify an exit code at the end of a build step, as it helps the CI/CD platform determine whether the step was successful or not.

package utils

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "path/filepath"

    drive "google.golang.org/api/drive/v3"

    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "golang.org/x/oauth2/jwt"
)

// ServiceAccount : Use Service account
func serviceAccount(credentialFile string) *http.Client {
    b, err := ioutil.ReadFile(credentialFile)
    if err != nil {
        log.Fatal(err)
    }
    var c = struct {
        Email      string `json:"client_email"`
        PrivateKey string `json:"private_key"`
    }{}
    json.Unmarshal(b, &c)
    config := &jwt.Config{
        Email:      c.Email,
        PrivateKey: []byte(c.PrivateKey),
        Scopes: []string{
            drive.DriveScope,
        },
        TokenURL: google.JWTTokenURL,
    }
    client := config.Client(oauth2.NoContext)
    return client
}

func UploadFile(serviceFile string, fileName string, folderId string) {
    filename := fileName                       // Filename
    baseMimeType := "application/octet-stream" // MimeType
    client := serviceAccount(serviceFile)      // Please set the json file of Service account.

    srv, err := drive.New(client)
    if err != nil {
        log.Fatalln(err)
    }
    file, err := os.Open(filename)
    if err != nil {
        log.Fatalln(err)
    }
    fileInf, err := file.Stat()
    if err != nil {
        log.Fatalln(err)
    }
    defer file.Close()
    // get base name from filename
    baseName := filepath.Base(filename)
    f := &drive.File{Name: baseName}
    if folderId != "" {
        f.Parents = []string{folderId}
    }
    res, err := srv.Files.
        Create(f).
        ResumableMedia(context.Background(), file, fileInf.Size(), baseMimeType).
        ProgressUpdater(func(now, size int64) { fmt.Printf("%d, %d\r", now, size) }).
        Do()
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Printf("Uploaded file %s with id %s\n", filename, res.Id)
}

// find files with the extension ending with *.apk
func FindFiles(extension string) ([]string, error) {
    files, err := filepath.Glob(extension)
    if err != nil {
        return nil, err
    }
    return files, nil
}
Enter fullscreen mode Exit fullscreen mode

This is a Go package called utils that contains several functions for interacting with Google Drive. The package defines the following functions:

  • serviceAccount: This function takes a file path as input and returns an HTTP client that can be used to authenticate requests to the Google Drive API using a service account. The function reads the contents of the file, which should be a JSON file containing the service account's email address and private key, and creates a jwt.Config object with this information. The function then uses the config to create an HTTP client and returns it.
  • UploadFile: This function takes three strings as input: a file path to a service account JSON file, a file path to the file to be uploaded, and the ID of a Google Drive folder. The function uses the serviceAccount function to create an HTTP client, then opens the file to be uploaded and creates a new file object in Google Drive with the contents of the uploaded file. The function also sets the parent folder of the new file to the folder specified by the folderId input.
  • FindFiles: This function takes a string as input and returns a slice of strings containing the file paths of all files in the current directory and its subdirectories that have the specified extension. The input string should contain a glob pattern, such as "*/.apk". The function uses the filepath.Glob function to search for files that match the pattern and returns the list of file paths.

An example bitrise.yml file that uses apk uploading to google drive is

---
format_version: '11'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: flutter
workflows:
  deploy:
    description: |
      Builds and deploys app using [Deploy to bitrise.io Step](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html#deploying-a-flutter-app).

      If you build for iOS, make sure to set up code signing secrets on Bitrise for a successful build.

      Next steps:
      - Check out [Getting started with Flutter apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html) for signing and deployment options.
      - Check out the [Code signing guide](https://devcenter.bitrise.io/en/code-signing.html) for iOS and Android
    steps:
    - git-clone@6: {}
    - certificate-and-profile-installer@1: {}
    - flutter-installer@0:
        inputs:
        - is_update: 'false'
    - cache-pull@2: {}
    - script@1:
        inputs:
        - content: |-
            #!/usr/bin/env bash
            # fail if any commands fails
            set -e
            # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully
            set -o pipefail
            # debug log
            set -x
            flutter upgrade
    - flutter-build@0:
        inputs:
        - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION"
        - platform: android
        - ios_output_type: archive
    - cache-push@2: {}
    - file-downloader@1:
        inputs:
        - destination: key.json
        - source: "$BITRISEIO_BITRISE_GOOGLE_SERVICE_JSON_URL"
    - git::https://github.com/FriendlyUser/bitrise-step-google-drive-uploader@main:
        title: Upload to google play
        inputs:
        - service_key_path: key.json
        - folder_id: 1MvS-z5JuIaMbAwsqMITeqnDNdtncEL7d
    - deploy-to-bitrise-io@2: {}
  primary:
    description: |
      Builds project and runs tests.

      Next steps:
      - Check out [Getting started with Flutter apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-flutter-apps.html).
    steps:
    - git-clone@6: {}
    - flutter-installer@0:
        inputs:
        - version: beta
    - cache-pull@2: {}
    - cache-push@2: {}
    - script@1:
        inputs:
        - content: |-
            #!/usr/bin/env bash
            # fail if any commands fails
            set -e
            # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully
            set -o pipefail
            # debug log
            set -x

            # write your script here
            echo "Hello World!"

            # or run a script from your repository, like:
            # bash ./path/to/script.sh
            # not just bash, e.g.:
            # ruby ./path/to/script.rb


            flutter upgrade
    - flutter-build@0: {}
    - deploy-to-bitrise-io@2: {}
meta:
  bitrise.io:
    stack: osx-xcode-14.1.x-ventura
app:
  envs:
  - opts:
      is_expand: false
    BITRISE_FLUTTER_PROJECT_LOCATION: "."
Enter fullscreen mode Exit fullscreen mode

This is a Bitrise configuration file written in YAML syntax. It defines two workflows: deploy and primary.

The deploy workflow includes several steps:

  1. git-clone@6: Clones the repository specified in the source input. certificate-and-profile-installer@1: Installs the necessary code signing certificates and profiles for the specified iOS development team.
  2. flutter-installer@0: Installs Flutter, the mobile app development framework.
  3. cache-pull@2: Pulls the specified cache from the Bitrise cache storage.
  4. script@1: Executes a custom script, in this case a Bash script that updates Flutter.
  5. flutter-build@0: Builds a Flutter app for the specified platform (Android in this case) and outputs an archive file.
  6. cache-push@2: Pushes the specified cache to the Bitrise cache storage.
  7. file-downloader@1: Downloads a file from the specified URL and saves it to the specified destination. git::https://github.com/FriendlyUser/bitrise-step-google-drive-uploader@main: Executes a step from a custom step library hosted on GitHub.
  8. deploy-to-bitrise-io@2: Deploys the built app to the Bitrise hosting platform.

References

Top comments (14)

Collapse
 
almexutrim23 profile image
almexutrim

To upload APKs to Google Drive in Bitrise, you can integrate the Google Drive API and utilize Bitrise's versatile workflow capabilities. First, ensure your workflow includes the necessary Google Drive API key and credentials for authentication. Implement a Bitrise Step that interacts with the Google Drive API, such as the "Google Drive Upload" step. Configure this step with the relevant parameters, including the APK file path and destination folder on Google Drive. As part of the process, consider adding a versioning strategy for organized file management. If you are dealing with the AAAD Apk Pro, make sure to appropriately name and label the APK file in your workflow, reflecting the specific version or build number. This integration enhances automation, allowing seamless and efficient uploading of AAAD Apk Pro files to Google Drive as part of your Bitrise CI/CD pipeline.

Collapse
 
afternoonteainldn_be47f86 profile image
afternoonteainldn

Integrating Google Drive API on Bitrise for APK uploads is a game-changer. It automates the process smoothly with steps like 'Google Drive Upload.' Afternoon Tea in London would be a great reward after a successful deployment using these efficient CI/CD tools!"

Collapse
 
deekal_shukla_69aaba8791a profile image
Deekal Shukla

APKs to Google Drive in Bitrise streamlines sharing builds. It's like having a virtual file cabinet. And in the midst of it all, a quick break at the Best Coffee Shop London could offer a refreshing perspective.

Collapse
 
bmpearllemon profile image
bm pearl lemon

Amazing insights on Aaad APK! It's tools like this that push the envelope in tech. Ever thought about how integrating business management solutions, similar to what a Workday consultant offers, could elevate our projects? Could be a real game-changer!

Collapse
 
bmpearllemon profile image
bm pearl lemon

Pets Lets Travel offers a hassle-free, universally recognized domain for educational and demonstration purposes. It's ideal for developers, educators, and content creators needing a neutral domain without registration or permission. Its simplicity and open access policy ensure easy integration into instructional materials, making it an invaluable tool for clear, focused demonstrations.

Thread Thread
 
balval profile image
balval

Pets Lets Travel offers a hassle-free domain for educational purposes, perfect for developers and educators. Consider Corporate Removal Group London for reliable relocation services.

Thread Thread
Collapse
 
pearllemon_leadsusa_1def7 profile image
Pearllemon Leadsusa

Uploading APKs to Google Drive in Bitrise can be tricky, but it's a valuable skill for app developers. I wonder if this lead generation agency USA has any tips or best practices for streamlining the process. Can't wait to find out

Collapse
 
lal profile image
val

Automating APK uploads to Google Drive via Bitrise, along with legal services London, simplifies deployment, saving developers time and reducing errors. This streamlined process not only enhances efficiency but also ensures that legal documents and contracts pertinent to app development are securely stored and easily accessible.

Collapse
 
pearllemoncateringteam profile image
Pearl Lemon catering

Uploading APKs to Google Drive in Bitrise is a common task for app developers seeking efficient storage and sharing solutions. If you're interested in exploring more ways to streamline your workflow, I recommend checking out party food catering. Just as Bitrise simplifies app deployment, top-notch catering services ensure seamless events with delicious food, catering to every occasion. Here's to productivity and culinary excellence!

Collapse
 
balval profile image
balval

I'm really impressed by the insights shared about Aaad APK! It's advancements like these that really make a difference in the world of technology. Have you ever considered how integrating business management solutions, similar to what a specific business management solution offers, could enhance our projects? It could make a huge impact! Also, if anyone has insights on relocation services in London, I'd love to hear about it!

Collapse
 
osteopilatesivrea_278ce4a profile image
osteopilatesivrea

Uploading APKs to Google Drive via Bitris.It's convenient for secure storage and sharing. And for some relaxation amidst tech tasks, there's osteopatia ivrea.

Collapse
 
deepak_shukla_d0071223783 profile image
Deepak Shukla

Uploading APKs to Google Drive in Bitrise can be quite handy, especially for sharing and storing app builds. Have you explored the Bitrise documentation for step-by-step instructions? If you encounter any hiccups along the way, Repair Services London
might have some tips to smooth out the process

Collapse
 
business_consultantfors profile image
Business consultant for small business

Uploading APKs to Google Drive via Bitrise can be a handy way to share builds and collaborate seamlessly. As Business Consultants for Small Businesses, leveraging efficient tools like Bitrise for app development is crucial for productivity. If you're looking to streamline this process, ensuring your workflows are optimized can make a big difference. How do you manage file uploads and sharing in your development projects

Collapse
 
vigizif profile image
majyh

Pet Lets Travel: Ideal for educational use. Simple and hassle-free. Consider Liverpool SEO for visibility.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.