[NEW] Add to F-Droid (#2171)

* create play and foss build

* update package.json to generate each build

* check1

* requested changes

* initial commit

* Update config.yml

* minor changes

* remove bugsnag from foss build

* remove bugsnag tasks from foss job

* fix stuck screen

* fixes

* update

* fix lint

* finalise 🚀

* requested changes

* share app for fdroid

* update

* use negation for builds

* requested change

* update share app

* fix issues due to latest sync

* add extra line

* fix lint

* update

* update

* fix bugsnag issue

* Update config.yml

* Fix store url

* Foss release instead of debug

* Add hold for foss

* Fix build

* requested changes

* update name and icons

* update

* fix

* Revert "Bump version to 4.11.0 (#2392)"

This reverts commit ea287980d9.

* finalise

Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Govind Dixit 2020-08-24 17:54:10 +05:30 committed by GitHub
parent 15f174b47b
commit b80d8a0eca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 582 additions and 98 deletions

View File

@ -119,7 +119,7 @@ jobs:
- save_cache: *save-npm-cache-linux - save_cache: *save-npm-cache-linux
# Android builds # Android builds
android-build: android-play-build:
<<: *defaults <<: *defaults
docker: docker:
- image: circleci/android:api-28-node - image: circleci/android:api-28-node
@ -178,12 +178,12 @@ jobs:
echo -e "export default { BUGSNAG_API_KEY: '$BUGSNAG_KEY' };" > ./config.js echo -e "export default { BUGSNAG_API_KEY: '$BUGSNAG_KEY' };" > ./config.js
- run: - run:
name: Build Android App name: Build Android Play App
command: | command: |
if [[ $KEYSTORE ]]; then if [[ $KEYSTORE ]]; then
bundle exec fastlane android release bundle exec fastlane android playRelease
else else
bundle exec fastlane android build bundle exec fastlane android playBuild
fi fi
working_directory: android working_directory: android
@ -194,8 +194,8 @@ jobs:
yarn generate-source-maps-android upload \ yarn generate-source-maps-android upload \
--api-key=$BUGSNAG_KEY \ --api-key=$BUGSNAG_KEY \
--app-version=$CIRCLE_BUILD_NUM \ --app-version=$CIRCLE_BUILD_NUM \
--minifiedFile=android/app/build/generated/assets/react/release/app.bundle \ --minifiedFile=android/app/build/generated/assets/react/play/release/app.bundle \
--source-map=android/app/build/generated/sourcemaps/react/release/app.bundle.map \ --source-map=android/app/build/generated/sourcemaps/react/play/release/app.bundle.map \
--minified-url=app.bundle \ --minified-url=app.bundle \
--upload-sources --upload-sources
fi fi
@ -213,6 +213,67 @@ jobs:
- android/fastlane/report.xml - android/fastlane/report.xml
- android/app/build/outputs - android/app/build/outputs
android-foss-build:
<<: *defaults
docker:
- image: circleci/android:api-28-node
environment:
JAVA_OPTS: '-Xms512m -Xmx2g'
GRADLE_OPTS: '-Xmx3g -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError"'
TERM: dumb
<<: *bash-env
steps:
- checkout
- run: *install-node
- restore_cache: *restore-npm-cache-linux
- run: *install-npm-modules
- run: *update-fastlane-android
- restore_cache: *restore-gradle-cache
- run:
name: Configure Gradle
command: |
echo -e "" > ./gradle.properties
# echo -e "android.enableAapt2=false" >> ./gradle.properties
echo -e "android.useAndroidX=true" >> ./gradle.properties
echo -e "android.enableJetifier=true" >> ./gradle.properties
echo -e "FLIPPER_VERSION=0.51.0" >> ./gradle.properties
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
if [[ $KEYSTORE ]]; then
echo $KEYSTORE_BASE64 | base64 --decode > ./app/$KEYSTORE
echo -e "KEYSTORE=$KEYSTORE" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$KEY_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
fi
working_directory: android
- run:
name: Build Android Foss App
command: bundle exec fastlane android fossRelease
working_directory: android
- store_artifacts:
path: android/app/build/outputs
- save_cache: *save-npm-cache-linux
- save_cache: *save-gradle-cache
- persist_to_workspace:
root: .
paths:
- android/fastlane/report.xml
- android/app/build/outputs
android-google-play-beta: android-google-play-beta:
<<: *defaults <<: *defaults
docker: docker:
@ -341,13 +402,20 @@ workflows:
requires: requires:
- ios-hold-testflight - ios-hold-testflight
- android-build: - android-play-build:
requires: requires:
- lint-testunit - lint-testunit
- android-hold-google-play-beta: - android-hold-google-play-beta:
type: approval type: approval
requires: requires:
- android-build - android-play-build
- android-google-play-beta: - android-google-play-beta:
requires: requires:
- android-hold-google-play-beta - android-hold-google-play-beta
- android-hold-foss-build:
type: approval
requires:
- lint-testunit
- android-foss-build:
requires:
- android-hold-foss-build

View File

@ -0,0 +1,3 @@
export default {
BuildConfigs: null
};

View File

@ -81,7 +81,6 @@ GEM
xcodeproj (>= 1.13.0, < 2.0.0) xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3) xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-appcenter (1.8.0)
gh_inspector (1.1.3) gh_inspector (1.1.3)
google-api-client (0.36.4) google-api-client (0.36.4)
addressable (~> 2.5, >= 2.5.1) addressable (~> 2.5, >= 2.5.1)
@ -156,6 +155,7 @@ GEM
uber (0.1.0) uber (0.1.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.7)
unf_ext (0.0.7.7-x64-mingw32) unf_ext (0.0.7.7-x64-mingw32)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
word_wrap (1.0.0) word_wrap (1.0.0)
@ -171,11 +171,11 @@ GEM
xcpretty (~> 0.2, >= 0.0.7) xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS PLATFORMS
ruby
x64-mingw32 x64-mingw32
DEPENDENCIES DEPENDENCIES
fastlane fastlane
fastlane-plugin-appcenter
BUNDLED WITH BUNDLED WITH
2.0.2 2.0.2

View File

@ -1,8 +1,13 @@
def taskRequests = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase()
def isPlay = !taskRequests.contains("foss")
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'com.bugsnag.android.gradle'
if (isPlay) {
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.bugsnag.android.gradle'
}
import com.android.build.OutputFile import com.android.build.OutputFile
@ -141,7 +146,9 @@ android {
versionCode VERSIONCODE as Integer versionCode VERSIONCODE as Integer
versionName "4.11.0" versionName "4.11.0"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] if (isPlay) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
}
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below! missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!
} }
@ -168,8 +175,10 @@ android {
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
setProguardFiles([getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro']) setProguardFiles([getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'])
signingConfig signingConfigs.release signingConfig signingConfigs.release
firebaseCrashlytics { if (isPlay) {
nativeSymbolUploadEnabled true firebaseCrashlytics {
nativeSymbolUploadEnabled true
}
} }
} }
} }
@ -182,6 +191,19 @@ android {
// } // }
// applicationVariants are e.g. debug, release // applicationVariants are e.g. debug, release
flavorDimensions "type"
productFlavors {
foss {
dimension = "type"
buildConfigField "boolean", "FDROID_BUILD", "true"
}
play {
dimension = "type"
buildConfigField "boolean", "FDROID_BUILD", "false"
}
}
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here: // For each separate APK per architecture, set a unique version code as described here:
@ -217,7 +239,7 @@ dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion //noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.react:react-native:+" // From node_modules
implementation "com.google.firebase:firebase-messaging:18.0.0" playImplementation "com.google.firebase:firebase-messaging:18.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni' exclude group:'com.facebook.fbjni'
@ -250,4 +272,7 @@ task copyDownloadableDepsToLibs(type: Copy) {
into 'libs' into 'libs'
} }
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
if (isPlay) {
apply plugin: 'com.google.gms.google-services'
}

View File

@ -0,0 +1,20 @@
package chat.rocket.reactnative;
import android.content.Context;
import android.os.Bundle;
import com.facebook.react.bridge.ReactApplicationContext;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.JsIOHelper;
import com.wix.reactnativenotifications.core.notification.PushNotification;
public class CustomPushNotification extends PushNotification {
public static ReactApplicationContext reactApplicationContext;
public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) {
super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper);
reactApplicationContext = new ReactApplicationContext(context);
}
}

View File

@ -0,0 +1,12 @@
package chat.rocket.reactnative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class DismissNotification extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}

View File

@ -0,0 +1,13 @@
package chat.rocket.reactnative;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class ReplyBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:pathData="M0,0h512v512h-512z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="512"
android:viewportHeight="512">
<group>
<clip-path android:pathData="M145,160h218v191.345h-218z M 0,0"/>
<path
android:pathData="M336.076,234.105L336.079,234.11C336.079,234.109 336.078,234.108 336.078,234.108C336.077,234.107 336.077,234.106 336.076,234.105ZM210.509,167.831C217.233,171.56 223.589,176.278 229.017,181.523C237.766,179.94 246.788,179.142 255.94,179.142C283.338,179.142 309.314,186.319 329.078,199.348C339.313,206.098 347.448,214.107 353.255,223.155C359.722,233.237 363,244.078 363,255.695C363,266.999 359.722,277.845 353.255,287.925C347.448,296.977 339.313,304.983 329.078,311.734C309.314,324.762 283.341,331.935 255.94,331.935C246.788,331.935 237.768,331.137 229.017,329.557C223.587,334.799 217.233,339.519 210.509,343.249C174.584,361.216 144.792,343.671 144.792,343.671C144.792,343.671 172.491,320.188 167.986,299.602C155.593,286.917 148.878,271.619 148.878,255.387C148.878,239.461 155.595,224.162 167.986,211.475C172.49,190.895 144.801,167.416 144.792,167.408C144.801,167.403 174.589,149.864 210.509,167.831Z"
android:fillColor="#DB2323"/>
<path
android:pathData="M189.04,291.26C176.71,281.543 169.31,269.108 169.31,255.555C169.31,224.456 208.278,199.245 256.348,199.245C304.418,199.245 343.386,224.456 343.386,255.555C343.386,286.655 304.418,311.866 256.348,311.866C244.501,311.866 233.206,310.335 222.912,307.561L215.386,314.82C211.296,318.765 206.503,322.334 201.507,325.147C194.884,328.399 188.345,330.174 181.875,330.715C182.24,330.052 182.576,329.379 182.937,328.715C190.478,314.822 192.512,302.337 189.04,291.26Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M214.708,268.127C207.625,268.127 201.883,262.413 201.883,255.364C201.883,248.316 207.625,242.602 214.708,242.602C221.791,242.602 227.533,248.316 227.533,255.364C227.533,262.413 221.791,268.127 214.708,268.127ZM255.998,268.127C248.915,268.127 243.173,262.413 243.173,255.364C243.173,248.316 248.915,242.602 255.998,242.602C263.08,242.602 268.822,248.316 268.822,255.364C268.822,262.413 263.08,268.127 255.998,268.127ZM297.287,268.127C290.204,268.127 284.462,262.413 284.462,255.364C284.462,248.316 290.204,242.602 297.287,242.602C304.37,242.602 310.112,248.316 310.112,255.364C310.112,262.413 304.37,268.127 297.287,268.127Z"
android:fillColor="#DB2323"/>
</group>
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
<!-- the background color. it can be a system color or a custom one defined in colors.xml -->
<item android:drawable="@color/splashBackground" />
<item>
<!-- the app logo, centered horizontally and vertically -->
<bitmap
android:src="@drawable/splash"
android:gravity="center" />
</item>
</layer-list>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="splashBackground" type="color">#000000</item>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primary_dark">#660B0B0B</color>
<item name="splashBackground" type="color">#eeeff1</item>
<item name="notification_text" type="color">#CC3333</item>
</resources>

View File

@ -0,0 +1,4 @@
<resources>
<string name="app_name">Rocket.Chat</string>
<string name="share_extension_name">Rocket.Chat</string>
</resources>

View File

@ -0,0 +1,28 @@
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:colorEdgeEffect">#aaaaaa</item>
<item name="colorPrimaryDark">@color/splashBackground</item>
<item name="android:navigationBarColor">@color/splashBackground</item>
</style>
<style name="Share.Window" parent="android:Theme">
<item name="android:windowEnterAnimation">@null</item>
<item name="android:windowExitAnimation">@null</item>
</style>
<style name="Theme.Share.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@color/primary_dark</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowAnimationStyle">@style/Share.Window</item>
</style>
<style name="BootTheme" parent="AppTheme">
<item name="android:background">@drawable/launch_screen</item>
<item name="colorPrimaryDark">@color/splashBackground</item>
<item name="android:navigationBarColor">@color/splashBackground</item>
</style>
</resources>

View File

@ -67,9 +67,6 @@
<data android:mimeType="*/*" /> <data android:mimeType="*/*" />
</intent-filter> </intent-filter>
</activity> </activity>
<meta-data
android:name="com.bugsnag.android.API_KEY"
android:value="${BugsnagAPIKey}" />
</application> </application>
</manifest> </manifest>

View File

@ -49,8 +49,10 @@ public class MainApplication extends Application implements ReactApplication, IN
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable") @SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages(); List<ReactPackage> packages = new PackageList(this).getPackages();
if (!BuildConfig.FDROID_BUILD) {
packages.add(new RNNotificationsPackage(MainApplication.this));
}
packages.add(new KeyboardInputPackage(MainApplication.this)); packages.add(new KeyboardInputPackage(MainApplication.this));
packages.add(new RNNotificationsPackage(MainApplication.this));
packages.add(new WatermelonDBPackage()); packages.add(new WatermelonDBPackage());
packages.add(new RNCViewPagerPackage()); packages.add(new RNCViewPagerPackage());
// packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider)); // packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));

View File

@ -0,0 +1,75 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="chat.rocket.reactnative">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".MainApplication"
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config"
>
<activity
android:name="com.zoontek.rnbootsplash.RNBootSplashActivity"
android:theme="@style/BootTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="go.rocket.chat" />
<data android:scheme="https" android:host="jitsi.rocket.chat" />
<data android:scheme="rocketchat" android:host="room" />
<data android:scheme="rocketchat" android:host="auth" />
<data android:scheme="rocketchat" android:host="jitsi.rocket.chat" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<receiver
android:name=".ReplyBroadcast"
android:enabled="true"
android:exported="false" />
<receiver
android:name=".DismissNotification"
android:enabled="true"
android:exported="false" >
</receiver>
<activity
android:noHistory="true"
android:name=".share.ShareActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/share_extension_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<meta-data
android:name="com.bugsnag.android.API_KEY"
android:value="${BugsnagAPIKey}" />
</application>
</manifest>

View File

@ -114,7 +114,7 @@ public class CustomPushNotification extends PushNotification {
Ejson ejson = new Gson().fromJson(bundle.getString("ejson", "{}"), Ejson.class); Ejson ejson = new Gson().fromJson(bundle.getString("ejson", "{}"), Ejson.class);
notification notification
.setContentTitle(title) .setContentTitle(title)
.setContentText(message) .setContentText(message)
.setContentIntent(intent) .setContentIntent(intent)
.setPriority(Notification.PRIORITY_HIGH) .setPriority(Notification.PRIORITY_HIGH)
@ -336,7 +336,7 @@ public class CustomPushNotification extends PushNotification {
intent.putExtra(NOTIFICATION_ID, notificationId); intent.putExtra(NOTIFICATION_ID, notificationId);
PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, 0); PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(mContext, notificationId, intent, 0);
notification.setDeleteIntent(dismissPendingIntent); notification.setDeleteIntent(dismissPendingIntent);
} }

View File

@ -0,0 +1,97 @@
package chat.rocket.reactnative;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.Callback;
import com.ammarahmed.mmkv.SecureKeystore;
import com.tencent.mmkv.MMKV;
import java.math.BigInteger;
class RNCallback implements Callback {
public void invoke(Object... args) {
}
}
class Utils {
static public String toHex(String arg) {
try {
return String.format("%x", new BigInteger(1, arg.getBytes("UTF-8")));
} catch (Exception e) {
return "";
}
}
}
public class Ejson {
String host;
String rid;
String type;
Sender sender;
String messageId;
String notificationType;
private MMKV mmkv;
private String TOKEN_KEY = "reactnativemeteor_usertoken-";
public Ejson() {
ReactApplicationContext reactApplicationContext = CustomPushNotification.reactApplicationContext;
// Start MMKV container
MMKV.initialize(reactApplicationContext);
SecureKeystore secureKeystore = new SecureKeystore(reactApplicationContext);
// https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
String alias = Utils.toHex("com.MMKV.default");
// Retrieve container password
secureKeystore.getSecureKey(alias, new RNCallback() {
@Override
public void invoke(Object... args) {
String error = (String) args[0];
if (error == null) {
String password = (String) args[1];
mmkv = MMKV.mmkvWithID("default", MMKV.SINGLE_PROCESS_MODE, password);
}
}
});
}
public String getAvatarUri() {
if (type == null) {
return null;
}
return serverURL() + "/avatar/" + this.sender.username + "?rc_token=" + token() + "&rc_uid=" + userId();
}
public String token() {
String userId = userId();
if (mmkv != null && userId != null) {
return mmkv.decodeString(TOKEN_KEY.concat(userId));
}
return "";
}
public String userId() {
String serverURL = serverURL();
if (mmkv != null && serverURL != null) {
return mmkv.decodeString(TOKEN_KEY.concat(serverURL));
}
return "";
}
public String serverURL() {
String url = this.host;
if (url != null && url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
return url;
}
public class Sender {
String username;
String _id;
}
}

View File

@ -17,15 +17,18 @@ buildscript {
url 'https://maven.fabric.io/public' url 'https://maven.fabric.io/public'
} }
} }
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
// NOTE: Do not place your application dependencies here; they belong def taskRequests = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase()
// in the individual module build.gradle files def isPlay = !taskRequests.contains("foss")
dependencies {
if (isPlay) {
classpath 'com.google.gms:google-services:4.2.0'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.0.0'
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
}
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View File

@ -16,20 +16,25 @@
default_platform(:android) default_platform(:android)
platform :android do platform :android do
desc "Build App for development" desc "Play build for development"
lane :build do lane :playBuild do
gradle(task: "assembleDebug") gradle(task: "assemblePlayDebug")
end end
desc "Build App for release" desc "Foss build for release"
lane :release do lane :fossRelease do
gradle(task: "bundleRelease") gradle(task: "assembleFossRelease")
end
desc "Play build for release"
lane :playRelease do
gradle(task: "bundlePlayRelease")
end end
desc "Upload App to Play Store Internal" desc "Upload App to Play Store Internal"
lane :beta do lane :beta do
upload_to_play_store( upload_to_play_store(
track: 'internal', track: 'internal',
aab: 'android/app/build/outputs/bundle/release/app-release.aab' aab: 'android/app/build/outputs/bundle/release/app-release.aab'
) )
end end

View File

@ -16,19 +16,24 @@ or alternatively using `brew cask install fastlane`
# Available Actions # Available Actions
## Android ## Android
### android build ### android playBuild
``` ```
fastlane android build fastlane android playBuild
``` ```
Build App for development Play build for development
### android release ### android fossRelease
``` ```
fastlane android release fastlane android fossRelease
``` ```
Build App for release Foss build for release
### android alpha ### android playRelease
``` ```
fastlane android alpha fastlane android playRelease
```
Play build for release
### android playAlpha
```
fastlane android playAlpha
``` ```
Upload App to Play store Upload App to Play store

View File

@ -0,0 +1,3 @@
import RNConfigReader from 'react-native-config-reader';
export const isFDroidBuild = RNConfigReader.FDROID_BUILD;

View File

@ -3,6 +3,7 @@ import { getBundleId, isIOS } from '../utils/deviceInfo';
const APP_STORE_ID = '1272915472'; const APP_STORE_ID = '1272915472';
export const PLAY_MARKET_LINK = `https://play.google.com/store/apps/details?id=${ getBundleId }`; export const PLAY_MARKET_LINK = `https://play.google.com/store/apps/details?id=${ getBundleId }`;
export const FDROID_MARKET_LINK = 'https://f-droid.org/en/packages/chat.rocket.android';
export const APP_STORE_LINK = `https://itunes.apple.com/app/id${ APP_STORE_ID }`; export const APP_STORE_LINK = `https://itunes.apple.com/app/id${ APP_STORE_ID }`;
export const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE'; export const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';
export const STORE_REVIEW_LINK = isIOS ? `itms-apps://itunes.apple.com/app/id${ APP_STORE_ID }?action=write-review` : `market://details?id=${ getBundleId }`; export const STORE_REVIEW_LINK = isIOS ? `itms-apps://itunes.apple.com/app/id${ APP_STORE_ID }?action=write-review` : `market://details?id=${ getBundleId }`;

View File

@ -36,6 +36,7 @@ import Toast from './containers/Toast';
import InAppNotification from './containers/InAppNotification'; import InAppNotification from './containers/InAppNotification';
import { ActionSheetProvider } from './containers/ActionSheet'; import { ActionSheetProvider } from './containers/ActionSheet';
import debounce from './utils/debounce'; import debounce from './utils/debounce';
import { isFDroidBuild } from './constants/environment';
RNScreens.enableScreens(); RNScreens.enableScreens();
@ -64,7 +65,9 @@ export default class Root extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.init(); this.init();
this.initCrashReport(); if (!isFDroidBuild) {
this.initCrashReport();
}
const { width, height, scale } = Dimensions.get('window'); const { width, height, scale } = Dimensions.get('window');
this.state = { this.state = {
theme: defaultTheme(), theme: defaultTheme(),

View File

@ -1,8 +1,8 @@
import EJSON from 'ejson'; import EJSON from 'ejson';
import PushNotification from './push'; import PushNotification from './push';
import store from '../../lib/createStore'; import store from '../../lib/createStore';
import { deepLinkingOpen } from '../../actions/deepLinking'; import { deepLinkingOpen } from '../../actions/deepLinking';
import { isFDroidBuild } from '../../constants/environment';
export const onNotification = (notification) => { export const onNotification = (notification) => {
if (notification) { if (notification) {
@ -38,8 +38,10 @@ export const onNotification = (notification) => {
export const getDeviceToken = () => PushNotification.getDeviceToken(); export const getDeviceToken = () => PushNotification.getDeviceToken();
export const setBadgeCount = count => PushNotification.setBadgeCount(count); export const setBadgeCount = count => PushNotification.setBadgeCount(count);
export const initializePushNotifications = () => { export const initializePushNotifications = () => {
setBadgeCount(); if (!isFDroidBuild) {
return PushNotification.configure({ setBadgeCount();
onNotification return PushNotification.configure({
}); onNotification
});
}
}; };

View File

@ -1,10 +1,17 @@
import { Client } from 'bugsnag-react-native'; import firebaseAnalytics from '@react-native-firebase/analytics';
import analytics from '@react-native-firebase/analytics'; import { isFDroidBuild } from '../../constants/environment';
import crashlytics from '@react-native-firebase/crashlytics';
import config from '../../../config'; import config from '../../../config';
import events from './events'; import events from './events';
const bugsnag = new Client(config.BUGSNAG_API_KEY); const analytics = firebaseAnalytics || '';
let bugsnag = '';
let crashlytics;
if (!isFDroidBuild) {
const { Client } = require('bugsnag-react-native');
crashlytics = require('@react-native-firebase/crashlytics');
bugsnag = new Client(config.BUGSNAG_API_KEY);
}
export { analytics }; export { analytics };
export const loggerConfig = bugsnag.config; export const loggerConfig = bugsnag.config;
@ -21,20 +28,24 @@ export const logServerVersion = (serverVersion) => {
export const logEvent = (eventName, payload) => { export const logEvent = (eventName, payload) => {
try { try {
analytics().logEvent(eventName, payload); if (!isFDroidBuild) {
leaveBreadcrumb(eventName, payload); analytics().logEvent(eventName, payload);
leaveBreadcrumb(eventName, payload);
}
} catch { } catch {
// Do nothing // Do nothing
} }
}; };
export const setCurrentScreen = (currentScreen) => { export const setCurrentScreen = (currentScreen) => {
analytics().setCurrentScreen(currentScreen); if (!isFDroidBuild) {
leaveBreadcrumb(currentScreen, { type: 'navigation' }); analytics().setCurrentScreen(currentScreen);
leaveBreadcrumb(currentScreen, { type: 'navigation' });
}
}; };
export default (e) => { export default (e) => {
if (e instanceof Error && e.message !== 'Aborted' && !__DEV__) { if (e instanceof Error && bugsnag && e.message !== 'Aborted' && !__DEV__) {
bugsnag.notify(e, (report) => { bugsnag.notify(e, (report) => {
report.metadata = { report.metadata = {
details: { details: {
@ -42,7 +53,9 @@ export default (e) => {
} }
}; };
}); });
crashlytics().recordError(e); if (!isFDroidBuild) {
crashlytics().recordError(e);
}
} else { } else {
console.log(e); console.log(e);
} }

View File

@ -5,6 +5,7 @@ import { isIOS } from './deviceInfo';
import I18n from '../i18n'; import I18n from '../i18n';
import { showErrorAlert } from './info'; import { showErrorAlert } from './info';
import { STORE_REVIEW_LINK } from '../constants/links'; import { STORE_REVIEW_LINK } from '../constants/links';
import { isFDroidBuild } from '../constants/environment';
import { logEvent, events } from './log'; import { logEvent, events } from './log';
const store = isIOS ? 'App Store' : 'Play Store'; const store = isIOS ? 'App Store' : 'Play Store';
@ -87,12 +88,14 @@ class ReviewApp {
positiveEventCount = 0; positiveEventCount = 0;
pushPositiveEvent = () => { pushPositiveEvent = () => {
if (this.positiveEventCount >= numberOfPositiveEvent) { if (!isFDroidBuild) {
return; if (this.positiveEventCount >= numberOfPositiveEvent) {
} return;
this.positiveEventCount += 1; }
if (this.positiveEventCount === numberOfPositiveEvent) { this.positiveEventCount += 1;
tryReview(); if (this.positiveEventCount === numberOfPositiveEvent) {
tryReview();
}
} }
} }
} }

View File

@ -29,7 +29,9 @@ import styles from './styles';
import { import {
loggerConfig, analytics, logEvent, events loggerConfig, analytics, logEvent, events
} from '../../utils/log'; } from '../../utils/log';
import { PLAY_MARKET_LINK, APP_STORE_LINK, LICENSE_LINK } from '../../constants/links'; import {
PLAY_MARKET_LINK, FDROID_MARKET_LINK, APP_STORE_LINK, LICENSE_LINK
} from '../../constants/links';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import SidebarView from '../SidebarView'; import SidebarView from '../SidebarView';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
@ -37,6 +39,8 @@ import EventEmitter from '../../utils/events';
import { appStart as appStartAction, ROOT_LOADING } from '../../actions/app'; import { appStart as appStartAction, ROOT_LOADING } from '../../actions/app';
import { onReviewPress } from '../../utils/review'; import { onReviewPress } from '../../utils/review';
import SafeAreaView from '../../containers/SafeAreaView'; import SafeAreaView from '../../containers/SafeAreaView';
import { isFDroidBuild } from '../../constants/environment';
const SectionSeparator = React.memo(({ theme }) => ( const SectionSeparator = React.memo(({ theme }) => (
<View <View
@ -110,12 +114,14 @@ class SettingsView extends React.Component {
AsyncStorage.setItem(CRASH_REPORT_KEY, JSON.stringify(value)); AsyncStorage.setItem(CRASH_REPORT_KEY, JSON.stringify(value));
const { toggleCrashReport } = this.props; const { toggleCrashReport } = this.props;
toggleCrashReport(value); toggleCrashReport(value);
loggerConfig.autoNotify = value; if (!isFDroidBuild) {
analytics().setAnalyticsCollectionEnabled(value); loggerConfig.autoNotify = value;
if (value) { analytics().setAnalyticsCollectionEnabled(value);
loggerConfig.clearBeforeSendCallbacks(); if (value) {
} else { loggerConfig.clearBeforeSendCallbacks();
loggerConfig.registerBeforeSendCallback(() => false); } else {
loggerConfig.registerBeforeSendCallback(() => false);
}
} }
} }
@ -142,8 +148,16 @@ class SettingsView extends React.Component {
} }
shareApp = () => { shareApp = () => {
logEvent(events.SE_SHARE_THIS_APP); let message;
Share.share({ message: isAndroid ? PLAY_MARKET_LINK : APP_STORE_LINK }); if (isAndroid) {
message = PLAY_MARKET_LINK;
if (isFDroidBuild) {
message = FDROID_MARKET_LINK;
}
} else {
message = APP_STORE_LINK;
}
Share.share({ message });
} }
copyServerVersion = () => { copyServerVersion = () => {
@ -230,14 +244,18 @@ class SettingsView extends React.Component {
theme={theme} theme={theme}
/> />
<Separator theme={theme} /> <Separator theme={theme} />
<ListItem {!isFDroidBuild ? (
title={I18n.t('Review_this_app')} <>
showActionIndicator <ListItem
onPress={onReviewPress} title={I18n.t('Review_this_app')}
testID='settings-view-review-app' showActionIndicator
right={this.renderDisclosure} onPress={onReviewPress}
theme={theme} testID='settings-view-review-app'
/> right={this.renderDisclosure}
theme={theme}
/>
</>
) : null}
<Separator theme={theme} /> <Separator theme={theme} />
<ListItem <ListItem
title={I18n.t('Share_this_app')} title={I18n.t('Share_this_app')}
@ -304,17 +322,33 @@ class SettingsView extends React.Component {
<SectionSeparator theme={theme} /> <SectionSeparator theme={theme} />
<ListItem {this.showLivechat ? (
title={I18n.t('Send_crash_report')} <>
testID='settings-view-crash-report' <ListItem
right={() => this.renderCrashReportSwitch()} title={I18n.t('Omnichannel')}
theme={theme} testID='settings-view-livechat'
/> right={() => this.renderLivechatSwitch()}
<Separator theme={theme} /> theme={theme}
<ItemInfo />
info={I18n.t('Crash_report_disclaimer')} <SectionSeparator theme={theme} />
theme={theme} </>
/> ) : null}
{!isFDroidBuild ? (
<>
<ListItem
title={I18n.t('Send_crash_report')}
testID='settings-view-crash-report'
right={() => this.renderCrashReportSwitch()}
theme={theme}
/>
<Separator theme={theme} />
<ItemInfo
info={I18n.t('Crash_report_disclaimer')}
theme={theme}
/>
</>
) : null}
<Separator theme={theme} /> <Separator theme={theme} />
<ListItem <ListItem

View File

@ -15,7 +15,9 @@
"precommit": "eslint . && jest", "precommit": "eslint . && jest",
"generate-source-maps-ios": "react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios-release.bundle --sourcemap-output ios-release.bundle.map", "generate-source-maps-ios": "react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios-release.bundle --sourcemap-output ios-release.bundle.map",
"generate-source-maps-android": "bugsnag-sourcemaps", "generate-source-maps-android": "bugsnag-sourcemaps",
"postinstall": "patch-package && jetify" "postinstall": "patch-package && jetify",
"play": "npx react-native run-android --variant=playDebug",
"foss": "npx react-native run-android --variant=fossDebug"
}, },
"husky": { "husky": {
"hooks": { "hooks": {
@ -69,6 +71,7 @@
"react-native-animatable": "^1.3.3", "react-native-animatable": "^1.3.3",
"react-native-appearance": "0.3.4", "react-native-appearance": "0.3.4",
"react-native-background-timer": "2.2.0", "react-native-background-timer": "2.2.0",
"react-native-config-reader": "^4.1.1",
"react-native-bootsplash": "2.2.5", "react-native-bootsplash": "2.2.5",
"react-native-console-time-polyfill": "^1.2.1", "react-native-console-time-polyfill": "^1.2.1",
"react-native-device-info": "5.6.2", "react-native-device-info": "5.6.2",

View File

@ -12731,6 +12731,11 @@ react-native-bootsplash@2.2.5:
jimp "0.14.0" jimp "0.14.0"
prompts "2.3.2" prompts "2.3.2"
react-native-config-reader@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/react-native-config-reader/-/react-native-config-reader-4.1.1.tgz#478b69e32adcc2e9a14f6ef5fa2cbbe012b9a27e"
integrity sha512-f+I9DkmJS5UYE++vgSBIFG/TUxxCy9GSpcDFmVj7TDNW9w+Nozc98pdene/VYFzg9QRE7hejRoA6yV1Lv+QbCw==
react-native-console-time-polyfill@^1.2.1: react-native-console-time-polyfill@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/react-native-console-time-polyfill/-/react-native-console-time-polyfill-1.2.1.tgz#3bf9a1d1d1ce3a05325fe1f2e5c4e5a1c25d910f" resolved "https://registry.yarnpkg.com/react-native-console-time-polyfill/-/react-native-console-time-polyfill-1.2.1.tgz#3bf9a1d1d1ce3a05325fe1f2e5c4e5a1c25d910f"