This guide is written using Signal-Android version 4.53.6
- Android Studio 4.0
- Java SE 14
- SDK 28
- NDK
- First clone the project source code:
git clone https://github.com/signalapp/Signal-Android.git && cd Signal-Android
- Comment out
distributionSha256Sum
ongradle/wrapper/gradle-wrapper.properties
and change the grale version from5.6.2
to6.4.1
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
#distributionSha256Sum=027fdd265d277bae65a0d349b6b8da02135b0b8e14ba891e26281fa877fe37a2
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
- Install the
21.0.6113669
NDK version link - Use 'Keystore Explorer’, edit
whisper.store
files (the password is "whisper" without quote), insert your all your server certificates there. - Update URL with own server in
app/build.gradle
(be sure to use https and don't include trailing slash). If you are having a hard time finding yourCloudfront domain
, you can find it in CloudFront console formated asrandom-id.cloudfront.net
.
...
defaultConfig {
versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName
minSdkVersion 19
targetSdkVersion 28
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
project.ext.set("archivesBaseName", "Signal");
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
buildConfigField "String", "SIGNAL_URL", "\"https://domain.com\""
buildConfigField "String", "STORAGE_URL", "\"https://cloudfrontdomain.com\""
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cloudfrontdomain.com\""
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://domain.com\""
buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"https://domain.com\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://domain.com\""
buildConfigField "String", "CONTENT_PROXY_HOST", "\"https://domain.com\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "USER_AGENT", "\"OWA\""
buildConfigField "boolean", "DEV_BUILD", "false"
buildConfigField "String", "MRENCLAVE", "\"cd6cfc342937b23b1bdd3bbf9721aa5615ac9ff50a75c5527d441cd3276826c9\""
buildConfigField "String", "KEY_BACKUP_ENCLAVE_NAME", "\"f2e2a5004794a6c1bac5c4949eadbc243dd02e02d1a93f10fe24584fb70815d8\""
buildConfigField "String", "KEY_BACKUP_MRENCLAVE", "\"f51f435802ada769e67aaf5744372bb7e7d519eecf996d335eb5b46b872b5789\""
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"public-key-generated-in-signal-server-step-3\""
buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
...
- update
UNIDENTIFIED_SENDER_TRUST_ROOT
(value is Public Key from when creating UnidentifiedDelivery of server’s config.yml) - Download
google-service.json
from Firebase, put it insideapp/
. - Update
app/src/main/res/values/firebase_messaging.xml
according to value fromgoogle-service.json
* - Update
ATTACHMENT_DOWNLOAD_PATH
andATTACHMENT_UPLOAD_PATH
inlibsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java
by deleting ‘attachments/‘ so attachment will be uploaded in root ( / ). If you don't want the attachments to be uploaded to root bucket, check the FAQ part of this guide. - Sync your project then build.
To create your own Signal-based Chat application, you need to rename the package. This is to prevent your app conflicting with signal on Play Store and on user's phone.
- Open Signal-Android in Android Studio.
Signal-Android package name is org.thoughtcrime.securesms
and in the project it's shown as a structure like this
app/src/main/java/org/thoughtcrime/securesms/
It is recommended that your desired package name also consist of three part, for example com.company.chatname
.
-
Right click on
securesms
directory, chooseRefactor
, then chooseRename
. When prompted, chooseRename Package
. Change it to your desiredchatname
. It is optional to chooseSearch in comments and strings
andSearch for text occurance
, you can leave it blank. -
After the search process is done, a window will appear on the bottom. Choose
Do Refactor
. -
It will take some time, after it is done, repeat step 2-3 to
thoughtcrime
andorg
. -
There's a chance some import could be left unchanged, to make sure, find
org.thoughtcrime.securesms
. If you found some, change it manually.
If you have done those step, you can already build your own app and install it to android. But the camera will not work because you haven't change the package name in native code.
- Change the package name in native code, find
org_thoughtcrime_securesms
and replace with your package name, remember to use underscore (_) like how it is before. It is located on:
app/jni/Android.mk
JNI_DIR := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native-utils
LOCAL_C_INCLUDES := $(JNI_DIR)/utils/
LOCAL_CFLAGS += -Wall
LOCAL_SRC_FILES := $(JNI_DIR)/utils/com_company_chatname_util_FileUtils.cpp
include $(BUILD_SHARED_LIBRARY)
app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.cpp
#include "com_company_chatname_util_FileUtils.h"
...
jint JNICALL Java_com_company_chatname_util_FileUtils_getFileDescriptorOwner
...
JNIEXPORT jint JNICALL Java_com_company_chatname_util_FileUtils_createMemoryFileDescriptor
...
app/jni/utils/org_thoughtcrime_securesms_util_FileUtils.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_company_chatname_util_FileUtils */
#ifndef _Included_com_company_chatname_util_FileUtils
#define _Included_com_company_chatname_util_FileUtils
...
/*
* Class: com_company_chatname_util_FileUtils
* Method: getFileDescriptorOwner
* Signature: (Ljava/io/FileDescriptor;)I
*/
JNIEXPORT jint JNICALL Java_com_company_chatname_util_FileUtils_getFileDescriptorOwner
(JNIEnv *, jclass, jobject);
/*
* Class: com_company_chatname_util_FileUtils
* Method: createMemoryFileDescriptor
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_company_chatname_util_FileUtils_createMemoryFileDescriptor
(JNIEnv *, jclass, jstring);
...
The last two files (.cpp and .h) also need to be renamed to follow your new package name, for example:
app/jni/utils/com_company_chatname_util_FileUtils.cpp
app/jni/utils/com_company_chatname_util_FileUtils.h
- Install NDK, and run this command in your directory
ndk-build
If the command is not recognized, it means your NDK installation has not been added to Environment Variable, then run it with absolute path.
- It will generate 4
libnative-utils.so
insideapp/jni
. Use it to replace the originals that located in here:
app
└── src
└── main
└── jniLibs
├── arm64-v8a
│ └── libnative-utils.so
├── armeabi-v7a
│ └── libnative-utils.so
├── x86
│ └── libnative-utils.so
└── x86_64
└── libnative-utils.so
- Update the package name that formated as
org/thoughtcrime/securesms
and replace with your package name, remember to use slash (/) like how it is before. It is located on:
app/lint-baseline.xml
...
file="src/main/java/com/company/chatname/util/dualsim/SubscriptionManagerCompat.java"
...
file="src/main/java/com/company/chatname/contacts/ContactSelectionListAdapter.java"
...
app/lint.xml
...
<ignore path="*/com/company/chatname/mediasend/camerax/VideoCapture.java" />
<ignore path="*/com/company/chatname/mediasend/camerax/CameraXModule.java" />
...
- Remember to update the application name in :
app/src/main/res/values/strings.xml
Q: How did I make Maps works?
A: On Android, search for com.google.android.geo.API_KEY
and change the value below that line with your own Google Maps API Key.
Q: How did I make Giphy/Sticker works?
A: For now, sticker file is not available publicly. Also, Giphy need content proxy to works, for now the content proxy source code is still not being shared publicly.
Q: What can I do so the attachments not uploaded to root bucket?
A: You still need to do Step 9
, but only remove the attachments
part from ATTACHMENT_UPLOAD_PATH
. Then modify your Signal-Server.
First open AttachmentControllerV2.java
located in service/src/main/java/org/whispersystems/textsecuregcm/controllers/
and find this line:
String objectName = String.valueOf(attachmentId);
Modify it to:
String objectName = "attachments/" + String.valueOf(attachmentId);
Then open AttachmentControllerTest.java
located in service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/
and find this line:
assertThat(descriptor.getKey()).isEqualTo(descriptor.getAttachmentIdString());
Modify it to:
assertThat(descriptor.getKey()).isEqualTo("attachments/" + descriptor.getAttachmentIdString());
Then re-build the server and run it.