diff --git a/android/app/build.gradle b/android/app/build.gradle
index 84ad671523..c56eeb88a7 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -38,7 +38,7 @@ android {
}
defaultConfig {
- applicationId "com.zulip.flutter"
+ applicationId "com.zulipmobile"
minSdkVersion 28
targetSdkVersion flutter.targetSdkVersion
// These are synced to local.properties from pubspec.yaml by the flutter tool.
diff --git a/docs/howto/push-notifications-ios-simulator.md b/docs/howto/push-notifications-ios-simulator.md
index d54bb20491..4ec1d6090a 100644
--- a/docs/howto/push-notifications-ios-simulator.md
+++ b/docs/howto/push-notifications-ios-simulator.md
@@ -64,15 +64,15 @@ receive a notification on the iOS Simulator for the zulip-flutter app.
Tapping on the notification should route to the respective conversation.
```shell-session
-$ xcrun simctl push [device-id] com.zulip.flutter [payload json path]
+$ xcrun simctl push [device-id] org.zulip.Zulip [payload json path]
```
Example output:
```shell-session
-$ xcrun simctl push 90CC33B2-679B-4053-B380-7B986A29F28C com.zulip.flutter ./dm.json
-Notification sent to 'com.zulip.flutter'
+$ xcrun simctl push 90CC33B2-679B-4053-B380-7B986A29F28C org.zulip.Zulip ./dm.json
+Notification sent to 'org.zulip.Zulip'
```
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 7df051a142..37f8231c8d 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -392,7 +392,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.zulip.flutter;
+ PRODUCT_BUNDLE_IDENTIFIER = org.zulip.Zulip;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -522,7 +522,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.zulip.flutter;
+ PRODUCT_BUNDLE_IDENTIFIER = org.zulip.Zulip;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -546,7 +546,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.zulip.flutter;
+ PRODUCT_BUNDLE_IDENTIFIER = org.zulip.Zulip;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index dbac5b20df..d86c7afca7 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -26,7 +26,7 @@
CFBundleURLName
- com.zulip.flutter
+ org.zulip.Zulip
CFBundleURLSchemes
zulip
diff --git a/lib/model/store.dart b/lib/model/store.dart
index 8fad731f5c..440634d76b 100644
--- a/lib/model/store.dart
+++ b/lib/model/store.dart
@@ -1078,7 +1078,7 @@ class LiveGlobalStore extends GlobalStore {
// What directory should we use?
// path_provider's getApplicationSupportDirectory:
// on Android, -> Flutter's PathUtils.getFilesDir -> https://developer.android.com/reference/android/content/Context#getFilesDir()
- // -> empirically /data/data/com.zulip.flutter/files/
+ // -> empirically /data/data/com.zulipmobile/files/
// on iOS, -> "Library/Application Support" via https://developer.apple.com/documentation/foundation/nssearchpathdirectory/nsapplicationsupportdirectory
// on Linux, -> "${XDG_DATA_HOME:-~/.local/share}/com.zulip.flutter/"
// All seem reasonable.
diff --git a/lib/notifications/display.dart b/lib/notifications/display.dart
index 74f0d1985a..7a66b1d19f 100644
--- a/lib/notifications/display.dart
+++ b/lib/notifications/display.dart
@@ -59,14 +59,14 @@ class NotificationChannelManager {
/// For example, for a resource `@raw/chime3`, where `raw` would be the
/// resource type and `chime3` would be the resource name it generates the
/// following URL:
- /// `android.resource://com.zulip.flutter/raw/chime3`
+ /// `android.resource://com.zulipmobile/raw/chime3`
///
/// Based on: https://stackoverflow.com/a/38340580
- static Uri _resourceUrlFromName({
+ static Future _resourceUrlFromName({
required String resourceTypeName,
required String resourceEntryName,
- }) {
- const packageName = 'com.zulip.flutter'; // TODO(#407)
+ }) async {
+ final packageInfo = await ZulipBinding.instance.packageInfo;
// URL scheme for Android resource url.
// See: https://developer.android.com/reference/android/content/ContentResolver#SCHEME_ANDROID_RESOURCE
@@ -74,9 +74,9 @@ class NotificationChannelManager {
return Uri(
scheme: schemeAndroidResource,
- host: packageName,
+ host: packageInfo!.packageName,
pathSegments: [resourceTypeName, resourceEntryName],
- );
+ ).toString();
}
/// Prepare our notification sounds; return a URL for our default sound.
@@ -87,9 +87,9 @@ class NotificationChannelManager {
/// Returns a URL for our default notification sound: either in shared storage
/// if we successfully copied it there, or else as our internal resource file.
static Future _ensureInitNotificationSounds() async {
- String defaultSoundUrl = _resourceUrlFromName(
+ String defaultSoundUrl = await _resourceUrlFromName(
resourceTypeName: 'raw',
- resourceEntryName: kDefaultNotificationSound.resourceName).toString();
+ resourceEntryName: kDefaultNotificationSound.resourceName);
final shouldUseResourceFile = switch (await ZulipBinding.instance.deviceInfo) {
// Before Android 10 Q, we don't attempt to put the sounds in shared media storage.
diff --git a/test/notifications/display_test.dart b/test/notifications/display_test.dart
index 7fe04c73ee..c4763b27ef 100644
--- a/test/notifications/display_test.dart
+++ b/test/notifications/display_test.dart
@@ -210,8 +210,8 @@ void main() {
NotificationChannelManager.kDefaultNotificationSound.resourceName;
String fakeStoredUrl(String resourceName) =>
testBinding.androidNotificationHost.fakeStoredNotificationSoundUrl(resourceName);
- String fakeResourceUrl(String resourceName) =>
- 'android.resource://com.zulip.flutter/raw/$resourceName';
+ String fakeResourceUrl({required String resourceName, String? packageName}) =>
+ 'android.resource://${packageName ?? eg.packageInfo().packageName}/raw/$resourceName';
test('on Android 28 (and lower) resource file is used for notification sound', () async {
addTearDown(testBinding.reset);
@@ -227,7 +227,30 @@ void main() {
.isEmpty();
check(androidNotificationHost.takeCreatedChannels())
.single
- .soundUrl.equals(fakeResourceUrl(defaultSoundResourceName));
+ .soundUrl.equals(fakeResourceUrl(resourceName: defaultSoundResourceName));
+ });
+
+ test('generates resource file URL from app package name', () async {
+ addTearDown(testBinding.reset);
+ final androidNotificationHost = testBinding.androidNotificationHost;
+
+ testBinding.packageInfoResult = eg.packageInfo(packageName: 'com.example.test');
+
+ // Force the default sound URL to be the resource file URL, by forcing
+ // the Android version to the one where we don't store sounds through the
+ // media store.
+ testBinding.deviceInfoResult =
+ const AndroidDeviceInfo(sdkInt: 28, release: '9');
+
+ await NotificationChannelManager.ensureChannel();
+ check(androidNotificationHost.takeCopySoundResourceToMediaStoreCalls())
+ .isEmpty();
+ check(androidNotificationHost.takeCreatedChannels())
+ .single
+ .soundUrl.equals(fakeResourceUrl(
+ resourceName: defaultSoundResourceName,
+ packageName: 'com.example.test',
+ ));
});
test('notification sound resource files are being copied to the media store', () async {
@@ -315,7 +338,7 @@ void main() {
.isEmpty();
check(androidNotificationHost.takeCreatedChannels())
.single
- .soundUrl.equals(fakeResourceUrl(defaultSoundResourceName));
+ .soundUrl.equals(fakeResourceUrl(resourceName: defaultSoundResourceName));
});
});