Skip to content

Commit 59bb5dc

Browse files
Fix Android app user agent for native requests
Native gRPC-web requests went out over Android's okhttp stack and were labelled with okhttp's default user agent. Add a gRPC-web interceptor that sets the CouchersNative User-Agent header on these requests. Also fix the "build unknown" segment: Constants.nativeBuildVersion is no longer populated on SDK 54, so read the native build version from expo-application instead. Co-authored-by: Aapeli <aapeliv@users.noreply.github.com>
1 parent 697c464 commit 59bb5dc

5 files changed

Lines changed: 26 additions & 2 deletions

File tree

app/mobile/jest.setup.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ jest.mock("expo-constants", () => ({
1515
gitHash: "abc12345",
1616
},
1717
},
18+
}));
19+
20+
// Mock expo-application globally
21+
jest.mock("expo-application", () => ({
1822
nativeBuildVersion: "42",
1923
}));
2024

app/mobile/package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/mobile/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@react-navigation/drawer": "^7.3.9",
3333
"@react-navigation/native": "^7.1.6",
3434
"expo": "~54.0.34",
35+
"expo-application": "~7.0.8",
3536
"expo-build-properties": "^1.0.10",
3637
"expo-constants": "~18.0.11",
3738
"expo-dev-client": "~6.0.21",

app/mobile/service/client.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AuthPromiseClient } from "@/proto/auth_grpc_web_pb";
33
import { NotificationsPromiseClient } from "@/proto/notifications_grpc_web_pb";
44

55
import isGrpcError from "@/service/utils/isGrpcError";
6+
import { applicationNameForUserAgent } from "@/utils/userAgent";
67

78
const URL =
89
process.env.NEXT_PUBLIC_API_BASE_URL ||
@@ -60,11 +61,27 @@ class TimeoutInterceptor {
6061
}
6162
}
6263

64+
// Native gRPC-web requests go out over the platform HTTP stack (okhttp on
65+
// Android), which would otherwise label them with its own user agent. Set our
66+
// own so the API sees the same identifier as the WebView.
67+
class UserAgentInterceptor {
68+
async intercept(
69+
request: Request<unknown, unknown>,
70+
invoker: (request: unknown) => unknown,
71+
) {
72+
const metadata = request.getMetadata();
73+
metadata["User-Agent"] = applicationNameForUserAgent;
74+
const response = await invoker(request);
75+
return response;
76+
}
77+
}
78+
6379
const authInterceptor = new AuthInterceptor();
6480
const timeoutInterceptor = new TimeoutInterceptor();
81+
const userAgentInterceptor = new UserAgentInterceptor();
6582

6683
const opts = {
67-
unaryInterceptors: [authInterceptor, timeoutInterceptor],
84+
unaryInterceptors: [authInterceptor, timeoutInterceptor, userAgentInterceptor],
6885
// this modifies the behaviour on the API so that it will send cookies on the requests
6986
withCredentials: true,
7087
/// TODO: streaming interceptor for auth https://grpc.io/blog/grpc-web-interceptor/

app/mobile/utils/userAgent.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import * as Application from "expo-application";
12
import Constants from "expo-constants";
23
import { Platform } from "react-native";
34

45
const appVersion = Constants.expoConfig?.version ?? "unknown";
56
const gitHash = Constants.expoConfig?.extra?.gitHash ?? "unknown";
6-
const nativeVersion = Constants.nativeBuildVersion ?? "unknown";
7+
const nativeVersion = Application.nativeBuildVersion ?? "unknown";
78

89
export const applicationNameForUserAgent = `CouchersNative/${appVersion} (${Platform.OS}; build ${nativeVersion}; ${gitHash})`;

0 commit comments

Comments
 (0)