77 tags :
88 - ' v*'
99
10+ env :
11+ JAVA_VERSION : ' 21'
12+ JAVA_DISTRIBUTION : ' temurin'
13+
1014jobs :
11- test-release :
12- if : github.ref == 'refs/heads/test'
15+ build :
1316 runs-on : ubuntu-latest
14- name : Test BenchmarkRelease Build
17+ name : Build APK
18+ outputs :
19+ version : ${{ steps.get-version.outputs.version }}
20+ is-release : ${{ steps.check-release.outputs.is-release }}
21+
1522 steps :
1623 - name : Checkout code
1724 uses : actions/checkout@v4
18- - name : Set up JDK 21
25+
26+ - name : Check if this is a release
27+ id : check-release
28+ run : |
29+ if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
30+ echo "is-release=true" >> $GITHUB_OUTPUT
31+ else
32+ echo "is-release=false" >> $GITHUB_OUTPUT
33+ fi
34+
35+ - name : Get version
36+ id : get-version
37+ run : |
38+ if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
39+ version="${{ github.ref_name }}"
40+ echo "version=$version" >> $GITHUB_OUTPUT
41+ else
42+ echo "version=test-${{ github.sha }}" >> $GITHUB_OUTPUT
43+ fi
44+
45+ - name : Set up JDK ${{ env.JAVA_VERSION }}
1946 uses : actions/setup-java@v4
2047 with :
21- distribution : ' temurin'
22- java-version : ' 21'
48+ distribution : ${{ env.JAVA_DISTRIBUTION }}
49+ java-version : ${{ env.JAVA_VERSION }}
50+
2351 - name : Cache Gradle packages
2452 uses : actions/cache@v4
2553 with :
@@ -29,49 +57,209 @@ jobs:
2957 key : gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
3058 restore-keys : |
3159 gradle-${{ runner.os }}-
60+
3261 - name : Grant execute permission for gradlew
3362 run : chmod +x ./gradlew
34- - name : Build benchmarkRelease APK
35- run : ./gradlew :app:assembleBenchmarkRelease
63+
64+ - name : Validate Gradle wrapper
65+ uses : gradle/wrapper-validation-action@v2
66+
67+ # For releases, create signed APK; for test builds, create unsigned APK
68+ - name : Build signed release APK
69+ if : steps.check-release.outputs.is-release == 'true'
70+ run : |
71+ echo "Building signed release APK..."
72+ ./gradlew :app:assembleBenchmarkRelease
73+ env :
74+ KEYSTORE_PASSWORD : ${{ secrets.KEYSTORE_PASSWORD }}
75+ KEY_ALIAS : ${{ secrets.KEY_ALIAS }}
76+ KEY_PASSWORD : ${{ secrets.KEY_PASSWORD }}
77+ KEYSTORE_FILE : ${{ secrets.KEYSTORE_FILE }}
78+
79+ - name : Build unsigned test APK
80+ if : steps.check-release.outputs.is-release == 'false'
81+ run : |
82+ echo "Building unsigned test APK..."
83+ ./gradlew :app:assembleBenchmarkRelease
84+
85+ - name : Setup keystore for signing (Release only)
86+ if : steps.check-release.outputs.is-release == 'true'
87+ run : |
88+ echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > keystore.jks
89+ echo "Keystore file created"
90+
91+ - name : Sign APK (Release only)
92+ if : steps.check-release.outputs.is-release == 'true'
93+ run : |
94+ # Find the APK file
95+ APK_FILE=$(find app/build/outputs/apk/benchmarkRelease -name "*.apk" | head -1)
96+ if [ -z "$APK_FILE" ]; then
97+ echo "Error: No APK file found"
98+ exit 1
99+ fi
100+
101+ echo "Found APK: $APK_FILE"
102+
103+ # Sign the APK
104+ $ANDROID_HOME/build-tools/*/apksigner sign \
105+ --ks keystore.jks \
106+ --ks-key-alias "${{ secrets.KEY_ALIAS }}" \
107+ --ks-pass pass:"${{ secrets.KEYSTORE_PASSWORD }}" \
108+ --key-pass pass:"${{ secrets.KEY_PASSWORD }}" \
109+ --out "${APK_FILE%.apk}-signed.apk" \
110+ "$APK_FILE"
111+
112+ # Verify the signature
113+ $ANDROID_HOME/build-tools/*/apksigner verify "${APK_FILE%.apk}-signed.apk"
114+
115+ echo "APK signed and verified successfully"
116+
117+ # Replace unsigned APK with signed one
118+ mv "${APK_FILE%.apk}-signed.apk" "$APK_FILE"
119+
120+ - name : Rename APK with version
121+ run : |
122+ APK_FILE=$(find app/build/outputs/apk/benchmarkRelease -name "*.apk" | head -1)
123+ if [ -z "$APK_FILE" ]; then
124+ echo "Error: No APK file found"
125+ exit 1
126+ fi
127+
128+ APK_DIR=$(dirname "$APK_FILE")
129+ APK_NAME=$(basename "$APK_FILE" .apk)
130+ VERSION="${{ steps.get-version.outputs.version }}"
131+
132+ if [[ "${{ steps.check-release.outputs.is-release }}" == "true" ]]; then
133+ NEW_NAME="ClipSync-Android-${VERSION}-signed.apk"
134+ else
135+ NEW_NAME="ClipSync-Android-${VERSION}-unsigned.apk"
136+ fi
137+
138+ mv "$APK_FILE" "$APK_DIR/$NEW_NAME"
139+ echo "APK renamed to: $NEW_NAME"
140+ echo "apk-path=$APK_DIR/$NEW_NAME" >> $GITHUB_OUTPUT
141+ id : rename-apk
142+
143+ - name : Get APK info
144+ run : |
145+ APK_FILE=$(find app/build/outputs/apk/benchmarkRelease -name "*.apk" | head -1)
146+ if [ -n "$APK_FILE" ]; then
147+ echo "APK Size: $(du -h "$APK_FILE" | cut -f1)"
148+ echo "APK Path: $APK_FILE"
149+
150+ # Get APK details using aapt if available
151+ if command -v aapt >/dev/null 2>&1; then
152+ echo "APK Package Info:"
153+ aapt dump badging "$APK_FILE" | grep -E "package:|application-label:|platformBuildVersionName"
154+ fi
155+ fi
156+
157+ - name : Cleanup keystore
158+ if : always() && steps.check-release.outputs.is-release == 'true'
159+ run : |
160+ if [ -f keystore.jks ]; then
161+ rm -f keystore.jks
162+ echo "Keystore file cleaned up"
163+ fi
164+
36165 - name : Upload APK artifact
37166 uses : actions/upload-artifact@v4
38167 with :
39- name : benchmark-release-apk
168+ name : clipsync-android-${{ steps.get-version.outputs.version }}
40169 path : app/build/outputs/apk/benchmarkRelease/*.apk
170+ retention-days : ${{ steps.check-release.outputs.is-release == 'true' && 90 || 30 }}
171+
172+ test-release :
173+ needs : build
174+ if : github.ref == 'refs/heads/test'
175+ runs-on : ubuntu-latest
176+ name : Test Release Upload
177+
178+ steps :
179+ - name : Download APK artifact
180+ uses : actions/download-artifact@v4
181+ with :
182+ name : clipsync-android-${{ needs.build.outputs.version }}
183+ path : ./apk/
184+
185+ - name : List test artifacts
186+ run : |
187+ echo "Test build artifacts:"
188+ find ./apk -name "*.apk" -exec ls -lh {} \;
41189
42190 release :
191+ needs : build
43192 if : startsWith(github.ref, 'refs/tags/v')
44193 runs-on : ubuntu-latest
45- name : Release BenchmarkRelease APK
194+ name : Create GitHub Release
195+
46196 steps :
47- - name : Checkout code
48- uses : actions/checkout@v4
49- - name : Set up JDK 21
50- uses : actions/setup-java@v4
51- with :
52- distribution : ' temurin'
53- java-version : ' 21'
54- - name : Cache Gradle packages
55- uses : actions/cache@v4
56- with :
57- path : |
58- ~/.gradle/caches
59- ~/.gradle/wrapper
60- key : gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
61- restore-keys : |
62- gradle-${{ runner.os }}-
63- - name : Grant execute permission for gradlew
64- run : chmod +x ./gradlew
65- - name : Build benchmarkRelease APK
66- run : ./gradlew :app:assembleBenchmarkRelease
67- - name : Upload APK artifact
68- uses : actions/upload-artifact@v4
197+ - name : Download APK artifact
198+ uses : actions/download-artifact@v4
69199 with :
70- name : benchmark-release-apk
71- path : app/build/outputs/apk/benchmarkRelease/*.apk
200+ name : clipsync-android-${{ needs.build.outputs.version }}
201+ path : ./apk/
202+
203+ - name : Verify release artifacts
204+ run : |
205+ echo "Release artifacts:"
206+ find ./apk -name "*.apk" -exec ls -lh {} \;
207+
208+ # Verify we have signed APK for release
209+ if ! find ./apk -name "*-signed.apk" | grep -q .; then
210+ echo "Warning: No signed APK found for release"
211+ else
212+ echo "Signed APK found for release"
213+ fi
214+
72215 - name : Create GitHub Release
73216 uses : softprops/action-gh-release@v2
74217 with :
75- files : app/build/outputs/apk/benchmarkRelease/*.apk
218+ name : ClipSync Android ${{ needs.build.outputs.version }}
219+ body : |
220+ # 🎉 Introducing ClipSync Android ${{ needs.build.outputs.version }} 🎉
221+
222+ Welcome to the very first official release of **ClipSync for Android**! 🚀
223+
224+ ClipSync bridges your clipboard between Android and Windows devices—instantly and wirelessly. Copy text on your phone, paste it on your PC, and vice versa. No cloud, no ads, just seamless Bluetooth-powered productivity!
225+
226+ ## What is ClipSync?
227+ ClipSync is a privacy-first clipboard sharing app that connects your Android and Windows devices over Bluetooth. Effortlessly share text between your phone and computer with a single tap—perfect for students, professionals, and anyone tired of emailing themselves snippets!
228+
229+ - 🔄 **Instant clipboard sharing** between Android and Windows
230+ - 🔒 **Private & local**: No data ever leaves your devices
231+ - 🌙 **Dark & Light themes**
232+ - ⚡ **Optimized for speed** with our special benchmarkRelease build
233+
234+ ## Installation
235+
236+ 1. Download the APK file below
237+ 2. Enable "Install from unknown sources" in your Android settings
238+ 3. Install the APK file
239+ 4. Pair with your Windows device (see README for details)
240+
241+ ## System Requirements
242+ - Android 7.0 (API level 24) or higher
243+ - Bluetooth capability (for device synchronization)
244+
245+ ## Security
246+ This APK is signed with our release key for security and authenticity. Your clipboard data stays on your devices—no servers, no snooping.
247+
248+ ## What's New
249+ This is our **first release**! 🎊
250+ - Android ↔ Windows clipboard sync
251+ - Bluetooth device discovery & pairing
252+ - Service-based background listening
253+ - Theme switching & intuitive UI
254+
255+ For more details, check the [CHANGELOG](CHANGELOG.md).
256+
257+ ---
258+ Thank you for trying ClipSync! If you love it, star the repo and share feedback. Happy syncing!
259+
260+ files : ./apk/*.apk
261+ draft : false
262+ prerelease : false
263+ generate_release_notes : true
76264 env :
77- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
265+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments