fix(mobile): separate group ids for separate app installs (#28448)
* separate group ids
* remove pigeon method
* Revert "remove pigeon method"
This reverts commit d699ff2094.
pull/28551/head
parent
6413495fb8
commit
7b9dab872b
|
|
@ -288,7 +288,6 @@ jobs:
|
|||
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
||||
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||
ENVIRONMENT: ${{ inputs.environment || 'development' }}
|
||||
BUNDLE_ID_SUFFIX: ${{ inputs.environment == 'production' && '' || 'development' }}
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
|
||||
FASTLANE_XCODEBUILD_SETTINGS_RETRIES: 6
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ interface NetworkApi {
|
|||
fun hasCertificate(): Boolean
|
||||
fun getClientPointer(): Long
|
||||
fun setRequestHeaders(headers: Map<String, String>, serverUrls: List<String>, token: String?)
|
||||
fun getAppGroupId(): String
|
||||
|
||||
companion object {
|
||||
/** The codec used by NetworkApi. */
|
||||
|
|
@ -430,6 +431,21 @@ interface NetworkApi {
|
|||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
val wrapped: List<Any?> = try {
|
||||
listOf(api.getAppGroupId())
|
||||
} catch (exception: Throwable) {
|
||||
NetworkPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class NetworkApiPlugin : FlutterPlugin, ActivityAware {
|
|||
private var networkApi: NetworkApiImpl? = null
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
networkApi = NetworkApiImpl()
|
||||
networkApi = NetworkApiImpl(binding.applicationContext)
|
||||
NetworkApi.setUp(binding.binaryMessenger, networkApi)
|
||||
}
|
||||
|
||||
|
|
@ -39,9 +39,11 @@ class NetworkApiPlugin : FlutterPlugin, ActivityAware {
|
|||
}
|
||||
}
|
||||
|
||||
private class NetworkApiImpl : NetworkApi {
|
||||
private class NetworkApiImpl(private val context: Context) : NetworkApi {
|
||||
var activity: Activity? = null
|
||||
|
||||
override fun getAppGroupId(): String = context.packageName
|
||||
|
||||
override fun addCertificate(clientData: ClientCertData, callback: (Result<Unit>) -> Unit) {
|
||||
try {
|
||||
HttpClientManager.setKeyEntry(clientData.data, clientData.password.toCharArray())
|
||||
|
|
|
|||
|
|
@ -718,6 +718,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share.profile;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
|
@ -750,7 +751,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -801,6 +801,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share.debug;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
|
|
@ -860,6 +861,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
|
|
@ -894,7 +896,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -924,7 +925,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
|
@ -1080,7 +1080,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
|
@ -1124,7 +1123,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
|
@ -1165,7 +1163,6 @@
|
|||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 240;
|
||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||
DEVELOPMENT_TEAM = 2W7AC6T8T5;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ protocol NetworkApi {
|
|||
func hasCertificate() throws -> Bool
|
||||
func getClientPointer() throws -> Int64
|
||||
func setRequestHeaders(headers: [String: String], serverUrls: [String], token: String?) throws
|
||||
func getAppGroupId() throws -> String
|
||||
}
|
||||
|
||||
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
||||
|
|
@ -388,5 +389,18 @@ class NetworkApiSetup {
|
|||
} else {
|
||||
setRequestHeadersChannel.setMessageHandler(nil)
|
||||
}
|
||||
let getAppGroupIdChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
getAppGroupIdChannel.setMessageHandler { _, reply in
|
||||
do {
|
||||
let result = try api.getAppGroupId()
|
||||
reply(wrapResult(result))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getAppGroupIdChannel.setMessageHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ class NetworkApiImpl: NetworkApi {
|
|||
return Int64(Int(bitPattern: pointer))
|
||||
}
|
||||
|
||||
func getAppGroupId() throws -> String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||
}
|
||||
|
||||
func setRequestHeaders(headers: [String : String], serverUrls: [String], token: String?) throws {
|
||||
URLSessionManager.setServerUrls(serverUrls)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import native_video_player
|
|||
let CLIENT_CERT_LABEL = "app.alextran.immich.client_identity"
|
||||
let HEADERS_KEY = "immich.request_headers"
|
||||
let SERVER_URLS_KEY = "immich.server_urls"
|
||||
let APP_GROUP = "group.app.immich.share"
|
||||
let APP_GROUP = Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||
let COOKIE_EXPIRY_DAYS: TimeInterval = 400
|
||||
|
||||
enum AuthCookie: CaseIterable {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.app.immich.share</string>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.app.immich.share</string>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.app.immich.share</string>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
let IMMICH_SHARE_GROUP = "group.app.immich.share"
|
||||
let IMMICH_SHARE_GROUP = Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as! String
|
||||
|
||||
enum WidgetError: Error, Codable {
|
||||
case noLogin
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AppGroupId</key>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.app.immich.share</string>
|
||||
<string>$(CUSTOM_GROUP_ID)</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -21,6 +21,7 @@ platform :ios do
|
|||
CODE_SIGN_IDENTITY = "Apple Distribution: FUTO Holdings, Inc. (#{TEAM_ID})"
|
||||
BASE_BUNDLE_ID = "app.alextran.immich"
|
||||
DEV_BUNDLE_ID = "tech.futo.immich.testflight"
|
||||
DEV_GROUP_ID = "group.app.immich.share.testflight"
|
||||
|
||||
# Helper method to get App Store Connect API key
|
||||
def get_api_key
|
||||
|
|
@ -33,6 +34,13 @@ platform :ios do
|
|||
)
|
||||
end
|
||||
|
||||
# Helper method to assemble xcargs with optional CUSTOM_GROUP_ID override
|
||||
def build_xcargs(group_id: nil)
|
||||
args = "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual"
|
||||
args += " CUSTOM_GROUP_ID='#{group_id}'" if group_id
|
||||
args
|
||||
end
|
||||
|
||||
# Helper method to get version from pubspec.yaml
|
||||
def get_version_from_pubspec
|
||||
require 'yaml'
|
||||
|
|
@ -89,7 +97,8 @@ end
|
|||
version_number: nil,
|
||||
profile_name_main:,
|
||||
profile_name_share:,
|
||||
profile_name_widget:
|
||||
profile_name_widget:,
|
||||
group_id: nil
|
||||
)
|
||||
app_identifier = base_bundle_id
|
||||
|
||||
|
|
@ -97,7 +106,7 @@ end
|
|||
if version_number
|
||||
increment_version_number(version_number: version_number)
|
||||
end
|
||||
|
||||
|
||||
# Increment build number
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number(
|
||||
|
|
@ -106,14 +115,14 @@ end
|
|||
) + 1,
|
||||
xcodeproj: "./Runner.xcodeproj"
|
||||
)
|
||||
|
||||
|
||||
# Build the app
|
||||
build_app(
|
||||
scheme: "Runner",
|
||||
workspace: "Runner.xcworkspace",
|
||||
configuration: configuration,
|
||||
export_method: "app-store",
|
||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
||||
xcargs: build_xcargs(group_id: group_id),
|
||||
export_options: {
|
||||
provisioningProfiles: {
|
||||
"#{app_identifier}" => profile_name_main,
|
||||
|
|
@ -165,7 +174,8 @@ end
|
|||
distribute_external: false,
|
||||
profile_name_main: main_profile_name,
|
||||
profile_name_share: share_profile_name,
|
||||
profile_name_widget: widget_profile_name
|
||||
profile_name_widget: widget_profile_name,
|
||||
group_id: DEV_GROUP_ID
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -274,7 +284,7 @@ end
|
|||
configuration: "Release",
|
||||
export_method: "app-store",
|
||||
skip_package_ipa: true,
|
||||
xcargs: "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual",
|
||||
xcargs: build_xcargs(group_id: DEV_GROUP_ID),
|
||||
export_options: {
|
||||
provisioningProfiles: {
|
||||
DEV_BUNDLE_ID => main_profile_name,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ const int kTimelineAssetLoadBatchSize = 1024;
|
|||
const int kTimelineAssetLoadOppositeSize = 64;
|
||||
|
||||
// Widget keys
|
||||
const String appShareGroupId = "group.app.immich.share";
|
||||
const String kWidgetAuthToken = "widget_auth_token";
|
||||
const String kWidgetServerEndpoint = "widget_server_url";
|
||||
const String kWidgetCustomHeaders = "widget_custom_headers";
|
||||
|
|
|
|||
|
|
@ -309,4 +309,23 @@ class NetworkApi {
|
|||
|
||||
_extractReplyValueOrThrow(pigeonVar_replyList, pigeonVar_channelName, isNullValid: true);
|
||||
}
|
||||
|
||||
Future<String> getAppGroupId() async {
|
||||
final pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.immich_mobile.NetworkApi.getAppGroupId$pigeonVar_messageChannelSuffix';
|
||||
final pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
|
||||
final pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
|
||||
final Object? pigeonVar_replyValue = _extractReplyValueOrThrow(
|
||||
pigeonVar_replyList,
|
||||
pigeonVar_channelName,
|
||||
isNullValid: false,
|
||||
);
|
||||
return pigeonVar_replyValue! as String;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:home_widget/home_widget.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||
|
||||
final widgetRepositoryProvider = Provider((_) => const WidgetRepository());
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ class WidgetRepository {
|
|||
await HomeWidget.updateWidget(iOSName: iosName, qualifiedAndroidName: androidName);
|
||||
}
|
||||
|
||||
Future<void> setAppGroupId(String appGroupId) async {
|
||||
await HomeWidget.setAppGroupId(appGroupId);
|
||||
Future<void> setAppGroupId() async {
|
||||
await HomeWidget.setAppGroupId(await networkApi.getAppGroupId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class WidgetService {
|
|||
const WidgetService(this._repository);
|
||||
|
||||
Future<void> writeCredentials(String serverURL, String sessionKey, String? customHeaders) async {
|
||||
await _repository.setAppGroupId(appShareGroupId);
|
||||
await _repository.setAppGroupId();
|
||||
await _repository.saveData(kWidgetServerEndpoint, serverURL);
|
||||
await _repository.saveData(kWidgetAuthToken, sessionKey);
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ class WidgetService {
|
|||
}
|
||||
|
||||
Future<void> clearCredentials() async {
|
||||
await _repository.setAppGroupId(appShareGroupId);
|
||||
await _repository.setAppGroupId();
|
||||
await _repository.saveData(kWidgetServerEndpoint, "");
|
||||
await _repository.saveData(kWidgetAuthToken, "");
|
||||
await _repository.saveData(kWidgetCustomHeaders, "");
|
||||
|
|
|
|||
|
|
@ -44,4 +44,6 @@ abstract class NetworkApi {
|
|||
int getClientPointer();
|
||||
|
||||
void setRequestHeaders(Map<String, String> headers, List<String> serverUrls, String? token);
|
||||
|
||||
String getAppGroupId();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue