Skip to content

Commit 89f5249

Browse files
committed
zapstore.yaml, ios id
1 parent 0cd35c5 commit 89f5249

6 files changed

Lines changed: 71 additions & 30 deletions

File tree

android/app/build.gradle

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,15 @@ android {
5252
signingConfigs {
5353
release {
5454
if (keystorePropertiesFile.exists()) {
55+
def releaseStoreType = keystoreProperties['storeType']?.toString()
56+
if (releaseStoreType) {
57+
storeType releaseStoreType
58+
}
59+
def releaseKeyPassword = releaseStoreType?.equalsIgnoreCase('pkcs12')
60+
? keystoreProperties['storePassword']
61+
: keystoreProperties['keyPassword']
5562
keyAlias keystoreProperties['keyAlias']
56-
keyPassword keystoreProperties['keyPassword']
63+
keyPassword releaseKeyPassword
5764
storeFile file(keystoreProperties['storeFile'])
5865
storePassword keystoreProperties['storePassword']
5966
}

ios/Runner.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@
536536
"$(PROJECT_DIR)/Frameworks/NdrFfi.xcframework/ios-arm64-simulator/libndr_ffi_sim.a",
537537
"$(PROJECT_DIR)/Frameworks/HashtreeFfi.xcframework/ios-arm64-simulator/libhashtree_ffi_sim.a",
538538
);
539-
PRODUCT_BUNDLE_IDENTIFIER = to.iris;
539+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat;
540540
PRODUCT_NAME = "$(TARGET_NAME)";
541541
SWIFT_ACTIVE_COMPILATION_CONDITIONS = NATIVE_RUST_FFI_ENABLED;
542542
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -555,7 +555,7 @@
555555
DEVELOPMENT_TEAM = J8PPJKD7TA;
556556
GENERATE_INFOPLIST_FILE = YES;
557557
MARKETING_VERSION = 1.0;
558-
PRODUCT_BUNDLE_IDENTIFIER = to.iris.RunnerTests;
558+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat.RunnerTests;
559559
PRODUCT_NAME = "$(TARGET_NAME)";
560560
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
561561
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -574,7 +574,7 @@
574574
DEVELOPMENT_TEAM = J8PPJKD7TA;
575575
GENERATE_INFOPLIST_FILE = YES;
576576
MARKETING_VERSION = 1.0;
577-
PRODUCT_BUNDLE_IDENTIFIER = to.iris.RunnerTests;
577+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat.RunnerTests;
578578
PRODUCT_NAME = "$(TARGET_NAME)";
579579
SWIFT_VERSION = 5.0;
580580
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -591,7 +591,7 @@
591591
DEVELOPMENT_TEAM = J8PPJKD7TA;
592592
GENERATE_INFOPLIST_FILE = YES;
593593
MARKETING_VERSION = 1.0;
594-
PRODUCT_BUNDLE_IDENTIFIER = to.iris.RunnerTests;
594+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat.RunnerTests;
595595
PRODUCT_NAME = "$(TARGET_NAME)";
596596
SWIFT_VERSION = 5.0;
597597
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -741,7 +741,7 @@
741741
"$(PROJECT_DIR)/Frameworks/NdrFfi.xcframework/ios-arm64-simulator/libndr_ffi_sim.a",
742742
"$(PROJECT_DIR)/Frameworks/HashtreeFfi.xcframework/ios-arm64-simulator/libhashtree_ffi_sim.a",
743743
);
744-
PRODUCT_BUNDLE_IDENTIFIER = to.iris;
744+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat;
745745
PRODUCT_NAME = "$(TARGET_NAME)";
746746
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG NATIVE_RUST_FFI_ENABLED";
747747
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -783,7 +783,7 @@
783783
"$(PROJECT_DIR)/Frameworks/NdrFfi.xcframework/ios-arm64-simulator/libndr_ffi_sim.a",
784784
"$(PROJECT_DIR)/Frameworks/HashtreeFfi.xcframework/ios-arm64-simulator/libhashtree_ffi_sim.a",
785785
);
786-
PRODUCT_BUNDLE_IDENTIFIER = to.iris;
786+
PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat;
787787
PRODUCT_NAME = "$(TARGET_NAME)";
788788
SWIFT_ACTIVE_COMPILATION_CONDITIONS = NATIVE_RUST_FFI_ENABLED;
789789
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

lib/core/services/mobile_push_subscription_service.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:firebase_messaging/firebase_messaging.dart';
77
import 'package:flutter/foundation.dart';
88
import 'package:http/http.dart' as http;
99
import 'package:nostr/nostr.dart' as nostr;
10+
import 'package:package_info_plus/package_info_plus.dart';
1011
import 'package:shared_preferences/shared_preferences.dart';
1112

1213
import '../../features/auth/domain/repositories/auth_repository.dart';
@@ -323,7 +324,7 @@ class MobilePushSubscriptionServiceImpl
323324
token: token,
324325
);
325326

326-
final payload = _buildPayload(
327+
final payload = await _buildPayload(
327328
messageAuthorPubkeysHex: messageAuthors,
328329
token: token,
329330
);
@@ -451,27 +452,39 @@ class MobilePushSubscriptionServiceImpl
451452
containsToken(subscription['apns_tokens'], token.apnsToken);
452453
}
453454

454-
Map<String, dynamic> _buildPayload({
455+
Future<Map<String, dynamic>> _buildPayload({
455456
required List<String> messageAuthorPubkeysHex,
456457
required MobilePushToken token,
457-
}) {
458+
}) async {
458459
final usesFcm = _tokenProvider.platformKey == 'android';
459460
final usesApns = _tokenProvider.platformKey == 'ios';
460461
final fcmToken = usesFcm ? token.fcmToken : null;
461462
final apnsToken = usesApns ? token.apnsToken : null;
463+
final apnsTopic = usesApns ? await _resolveIosBundleId() : null;
462464

463465
return <String, dynamic>{
464466
'webhooks': const <String>[],
465467
'web_push_subscriptions': const <Object>[],
466468
'fcm_tokens': fcmToken == null ? const <String>[] : <String>[fcmToken],
467469
'apns_tokens': apnsToken == null ? const <String>[] : <String>[apnsToken],
470+
if (apnsTopic != null) 'apns_topic': apnsTopic,
468471
'filter': <String, dynamic>{
469472
'kinds': <int>[_dmEventKind],
470473
'authors': messageAuthorPubkeysHex,
471474
},
472475
};
473476
}
474477

478+
Future<String?> _resolveIosBundleId() async {
479+
try {
480+
final packageName = (await PackageInfo.fromPlatform()).packageName.trim();
481+
if (packageName.isEmpty) return null;
482+
return packageName;
483+
} catch (_) {
484+
return null;
485+
}
486+
}
487+
475488
Future<http.Response> _authedRequest({
476489
required String method,
477490
required String path,

test/unit/core/services/mobile_push_subscription_service_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:iris_chat/core/services/mobile_push_subscription_service.dart';
1010
import 'package:iris_chat/features/auth/domain/models/identity.dart';
1111
import 'package:iris_chat/features/auth/domain/repositories/auth_repository.dart';
1212
import 'package:mocktail/mocktail.dart';
13+
import 'package:package_info_plus/package_info_plus.dart';
1314
import 'package:shared_preferences/shared_preferences.dart';
1415

1516
class _FakeAuthRepository implements AuthRepository {
@@ -564,6 +565,13 @@ void main() {
564565

565566
test('creates subscription with APNS token only on iOS', () async {
566567
SharedPreferences.setMockInitialValues({});
568+
PackageInfo.setMockInitialValues(
569+
appName: 'Iris Chat',
570+
packageName: 'to.iris.chat',
571+
version: '1.0.0',
572+
buildNumber: '1',
573+
buildSignature: '',
574+
);
567575
late Map<String, dynamic> postedBody;
568576

569577
final client = MockClient((request) async {
@@ -600,6 +608,7 @@ void main() {
600608

601609
expect(postedBody['fcm_tokens'], isEmpty);
602610
expect(postedBody['apns_tokens'], [apnsToken]);
611+
expect(postedBody['apns_topic'], 'to.iris.chat');
603612
expect(postedBody['filter']['authors'], [messageAuthorPubkey]);
604613
});
605614
});

test/unit/ios/mobile_push_native_configuration_test.dart

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@ import 'package:flutter_test/flutter_test.dart';
44

55
void main() {
66
group('iOS mobile push configuration', () {
7-
test('bundle id aligns with the live APNS topic without Firebase plist', () {
8-
final projectFile = File('ios/Runner.xcodeproj/project.pbxproj');
9-
final appDelegateFile = File('ios/Runner/AppDelegate.swift');
10-
final plistFile = File('ios/Runner/GoogleService-Info.plist');
7+
test(
8+
'bundle id aligns with the live APNS topic without Firebase plist',
9+
() {
10+
final projectFile = File('ios/Runner.xcodeproj/project.pbxproj');
11+
final appDelegateFile = File('ios/Runner/AppDelegate.swift');
12+
final plistFile = File('ios/Runner/GoogleService-Info.plist');
1113

12-
expect(projectFile.existsSync(), isTrue);
13-
expect(appDelegateFile.existsSync(), isTrue);
14-
expect(plistFile.existsSync(), isFalse);
14+
expect(projectFile.existsSync(), isTrue);
15+
expect(appDelegateFile.existsSync(), isTrue);
16+
expect(plistFile.existsSync(), isFalse);
1517

16-
final projectContent = projectFile.readAsStringSync();
17-
final appDelegateContent = appDelegateFile.readAsStringSync();
18+
final projectContent = projectFile.readAsStringSync();
19+
final appDelegateContent = appDelegateFile.readAsStringSync();
1820

19-
expect(projectContent, contains('PRODUCT_BUNDLE_IDENTIFIER = to.iris;'));
20-
expect(
21-
appDelegateContent,
22-
contains('name: mobilePushChannelName'),
23-
);
24-
expect(
25-
appDelegateContent,
26-
contains('case "getApnsToken"'),
27-
);
28-
expect(projectContent, isNot(contains('GoogleService-Info.plist')));
29-
});
21+
expect(
22+
projectContent,
23+
contains('PRODUCT_BUNDLE_IDENTIFIER = to.iris.chat;'),
24+
);
25+
expect(appDelegateContent, contains('name: mobilePushChannelName'));
26+
expect(appDelegateContent, contains('case "getApnsToken"'));
27+
expect(projectContent, isNot(contains('GoogleService-Info.plist')));
28+
},
29+
);
3030

3131
test('app target enables push entitlements and remote registration', () {
3232
final entitlementsFile = File('ios/Runner/Runner.entitlements');

zapstore.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Iris Chat
2+
summary: End-to-end encrypted chat app using Nostr Double Ratchet.
3+
repository: https://github.com/irislib/iris-chat-flutter
4+
release_source: build/app/outputs/flutter-apk/app-release.apk
5+
website: https://chat.iris.to
6+
icon: assets/icons/app_icon.png
7+
license: MIT
8+
tags:
9+
- nostr
10+
metadata_sources:
11+
- github
12+
description: End-to-end encrypted chat app using the Nostr Double Ratchet protocol.

0 commit comments

Comments
 (0)