Skip to content

Commit 09eaf7e

Browse files
SDK Samplesisaaccase
SDK Samples
authored andcommitted
No public description
PiperOrigin-RevId: 700706989
1 parent 036e6f8 commit 09eaf7e

File tree

34 files changed

+1572
-124
lines changed

34 files changed

+1572
-124
lines changed

README.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
1-
Android SearchInApps API sample apps
1+
SearchInApps API sample apps
22
============
33

44
Introduction
55
------------
66

7-
Android SearchInApps API allows apps to get Google related search suggestions and trending searches.
8-
These apps provide fully functional examples of integrating with SearchInApps SDK.
7+
The SearchInApps API allows apps to get Google related search suggestions and trending searches.
8+
These apps provide fully functional examples of integrating with the SearchInApps SDK.
99

1010
Getting started
1111
---------------
1212
Clone this project to your workstation using a git client. You can use the
1313
[instructions from GitHub](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/cloning-a-repository)
1414
if you need guidance.
1515

16-
This project uses the Gradle build system. To build this project, use the
16+
### Android ###
17+
The Android projects use the Gradle build system. To build this project, use the
1718
`gradlew build` command or use "Import Project" in Android Studio.
1819

1920
For more resources on learning Android development, visit the
2021
[Developer Guides](https://developer.android.com/guide/) at
2122
[developer.android.com](https://developer.android.com).
2223

24+
### iOS ###
25+
The iOS projects are Xcode projects that use [cocoapods](https://cocoapods.org/)
26+
for package dependency.
27+
28+
For more resources on learning iOS development, visit Apple's
29+
[documentation](https://developer.apple.com/documentation/) at
30+
[developer.apple.com](https://developer.apple.com).
31+
2332
Prerequisites
2433
-------------
2534

26-
To let these sample apps work properly, please follow the [SearchInApps Android SDK developer guide](https://developers.google.com/search-in-apps/android) to get your client id and api key, and put them into the sample apps' AndroidManifest.xml file.
35+
The sample apps need a **client id** and **api key** to work. Please follow the [SearchInApps Android SDK developer guide](https://developers.google.com/search-in-apps/android) or [SearchInApps iOS SDK developer guide](https://developers.google.com/search-in-apps/ios) to get your client id and api key.
36+
37+
For Android, insert the **client id** and **api key** into the sample apps' AndroidManifest.xml file, for iOS insert it into the project's Info.plist.
2738

28-
For Java developers
39+
For Android Java developers
2940
-------------------
3041

3142
The Android View sample application is contained in the view/ directory. It is written fully in Java. The detailed information about the SearchInApps SDK's Java classes can be found [here](https://developers.google.com/search-in-apps/android/reference/com/google/android/libraries/searchinapps/package-summary).
3243

33-
For Jetpack Compose developers
44+
For Android Jetpack Compose developers
3445
------------------------------
3546

3647
The Jetpack Compose sample application is contained in the compose/ directory. It is written fully in Kotlin. The detailed information about the SearchInApps SDK's Kotlin classes can be found [here](https://developers.google.com/search-in-apps/android/reference/kotlin/com/google/android/libraries/searchinapps/package-summary).
3748

49+
For iOS SwiftUI developers
50+
------------------------------
51+
The SwiftUI sample application is contained in the swiftui/ directory. The detailed information about the SearchInApps SDK's Swift classes can be found [here](https://developers.google.com/search-in-apps/ios/reference/api/swift_reference/Classes/ContextualSearchRuntime).
52+
53+
3854
Support
3955
-------
4056

compose/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ android {
5454

5555
dependencies {
5656
implementation "com.google.android.gms:play-services-oss-licenses:17.0.0"
57-
implementation "com.google.android.libraries.searchinapps:searchinapps:0.3.0"
57+
implementation "com.google.android.libraries.searchinapps:searchinapps:0.4.1"
5858

5959
implementation "androidx.activity:activity-compose:1.7.0"
6060
implementation "androidx.appcompat:appcompat:1.4.1"

compose/app/src/main/java/com/google/samples/quickstart/searchinapps/compose/MainActivity.kt

Lines changed: 109 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ import androidx.compose.foundation.layout.height
2727
import androidx.compose.foundation.layout.padding
2828
import androidx.compose.foundation.layout.width
2929
import androidx.compose.foundation.layout.wrapContentWidth
30+
import androidx.compose.foundation.rememberScrollState
31+
import androidx.compose.foundation.verticalScroll
3032
import androidx.compose.material3.Button
3133
import androidx.compose.material3.MaterialTheme
3234
import androidx.compose.material3.OutlinedTextField
3335
import androidx.compose.material3.RadioButton
3436
import androidx.compose.material3.Surface
3537
import androidx.compose.material3.Text
3638
import androidx.compose.runtime.Composable
39+
import androidx.compose.runtime.DisposableEffect
3740
import androidx.compose.runtime.getValue
3841
import androidx.compose.runtime.mutableStateOf
3942
import androidx.compose.runtime.remember
@@ -47,21 +50,23 @@ import androidx.compose.ui.tooling.preview.Preview
4750
import androidx.compose.ui.viewinterop.AndroidView
4851
import androidx.lifecycle.compose.collectAsStateWithLifecycle
4952
import androidx.lifecycle.viewmodel.compose.viewModel
53+
import com.google.android.libraries.searchinapps.GetSearchContentViewGeneratorCallback
54+
import com.google.android.libraries.searchinapps.GetSearchContentViewOptions
5055
import com.google.android.libraries.searchinapps.GetSearchSuggestionsViewGeneratorCallback
5156
import com.google.android.libraries.searchinapps.GetSearchSuggestionsViewOptions
5257
import com.google.android.libraries.searchinapps.GetTrendingSearchesViewOptions
5358
import com.google.android.libraries.searchinapps.LocationContext
5459
import com.google.android.libraries.searchinapps.LocationContext.CircularArea
5560
import com.google.android.libraries.searchinapps.LocationContext.GeographicalRestrictions
5661
import com.google.android.libraries.searchinapps.LocationContext.LatLng
62+
import com.google.android.libraries.searchinapps.SearchContentViewGenerator
63+
import com.google.android.libraries.searchinapps.SearchContentViewOptions
5764
import com.google.android.libraries.searchinapps.SearchInAppsService
5865
import com.google.android.libraries.searchinapps.SearchSuggestionsViewGenerator
5966
import com.google.android.libraries.searchinapps.SearchSuggestionsViewOptions
6067

6168
/** Jetpack activity demonstrating the usage of SearchInAppsService API. */
6269
class MainActivity : AppCompatActivity() {
63-
private var service: SearchInAppsService? = null
64-
6570
override fun onCreate(savedInstanceState: Bundle?) {
6671
super.onCreate(savedInstanceState)
6772
setContent {
@@ -91,12 +96,22 @@ class MainActivity : AppCompatActivity() {
9196
viewModel: SearchInAppsViewModel = viewModel(),
9297
) {
9398
var context = LocalContext.current
94-
if (service == null) {
95-
service = SearchInAppsService.create(context)
99+
var service by remember {
100+
mutableStateOf<SearchInAppsService?>(SearchInAppsService.create(context))
96101
}
97102
var textInput by remember { mutableStateOf("") }
98103
var locationInput by remember { mutableStateOf("") }
104+
var searchRepeatInput by remember { mutableStateOf("") }
105+
106+
var searchContentBlockNumber by remember { mutableStateOf(0) }
99107

108+
val viewSuggestionsGenerator by
109+
viewModel.getSearchSuggestionsViewGenerator().collectAsStateWithLifecycle()
110+
val viewContentGenerator by
111+
viewModel.getSearchContentViewGenerator().collectAsStateWithLifecycle()
112+
viewContentGenerator?.let { viewContentGenerator ->
113+
searchContentBlockNumber = viewContentGenerator.getSearchContentBlockCount()
114+
}
100115
val layout by viewModel.getLayout().collectAsStateWithLifecycle()
101116

102117
var radioOptions =
@@ -106,6 +121,8 @@ class MainActivity : AppCompatActivity() {
106121
stringResource(R.string.tiling_layout),
107122
)
108123

124+
DisposableEffect(Unit) { onDispose { service?.shutDown() } }
125+
109126
Column {
110127
Row(verticalAlignment = Alignment.CenterVertically) {
111128
OutlinedTextField(
@@ -125,6 +142,15 @@ class MainActivity : AppCompatActivity() {
125142
)
126143
}
127144

145+
Row(verticalAlignment = Alignment.CenterVertically) {
146+
OutlinedTextField(
147+
value = searchRepeatInput,
148+
onValueChange = { searchRepeatInput = it },
149+
label = { Text(stringResource(R.string.search_repeat_hint)) },
150+
modifier = Modifier.fillMaxWidth(),
151+
)
152+
}
153+
128154
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.vertical_spacer_height)))
129155

130156
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -195,6 +221,56 @@ class MainActivity : AppCompatActivity() {
195221

196222
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.vertical_spacer_height)))
197223

224+
val searchContentCallback =
225+
object : GetSearchContentViewGeneratorCallback() {
226+
override fun onSuccess(generator: SearchContentViewGenerator) {
227+
viewModel.setSearchContentViewGenerator(generator)
228+
searchContentBlockNumber = generator.getSearchContentBlockCount()
229+
}
230+
231+
override fun onError(errorMessage: String) {
232+
Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show()
233+
}
234+
235+
override fun onLoadMoreSearchContentSuccess(generator: SearchContentViewGenerator) {
236+
searchContentBlockNumber = generator.getSearchContentBlockCount()
237+
}
238+
239+
override fun onLoadMoreSearchContentError(errorMessage: String) {
240+
Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show()
241+
}
242+
}
243+
Row(verticalAlignment = Alignment.CenterVertically) {
244+
Button(
245+
modifier = Modifier.wrapContentWidth(),
246+
onClick = {
247+
var options: GetSearchContentViewOptions =
248+
GetSearchContentViewOptions()
249+
.setSearchRepeatContext(searchRepeatInput)
250+
.setNumberOfBlocksToRequest(3)
251+
.setSearchContentViewOptions(SearchContentViewOptions().setLayout(layout))
252+
253+
service?.getSearchContentView(options, searchContentCallback)
254+
},
255+
) {
256+
Text(stringResource(R.string.search_content))
257+
}
258+
259+
Spacer(modifier = Modifier.width(dimensionResource(R.dimen.horizontal_spacer_width)))
260+
261+
Button(
262+
onClick = {
263+
viewContentGenerator?.let { viewContentGenerator ->
264+
viewContentGenerator.loadMoreSearchContent(searchContentCallback)
265+
}
266+
}
267+
) {
268+
Text(stringResource(R.string.load_more_content))
269+
}
270+
}
271+
272+
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.vertical_spacer_height)))
273+
198274
Row {
199275
radioOptions.forEach { currentLayout ->
200276
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -206,27 +282,48 @@ class MainActivity : AppCompatActivity() {
206282
}
207283
}
208284
}
209-
val viewGenerator by
210-
viewModel.getSearchSuggestionsViewGenerator().collectAsStateWithLifecycle()
211-
ChipGroupUI(layout, viewGenerator)
285+
ChipGroupUI(layout, viewSuggestionsGenerator)
286+
SearchContentUI(layout, viewContentGenerator, searchContentBlockNumber)
212287
}
213288
}
214289

215290
@Composable
216291
fun ChipGroupUI(
217292
layout: SearchSuggestionsViewOptions.Layout,
218-
viewGenerator: SearchSuggestionsViewGenerator?,
293+
viewSuggestionsGenerator: SearchSuggestionsViewGenerator?,
219294
) {
220-
viewGenerator?.let { viewGenerator ->
221-
viewGenerator.getViewOptions().setLayout(layout)
295+
viewSuggestionsGenerator?.let { viewSuggestionsGenerator ->
296+
viewSuggestionsGenerator.getViewOptions().setLayout(layout)
222297
var context = LocalContext.current
223298
AndroidView(
224-
factory = { context -> viewGenerator.populateView(context) },
225-
update = { view -> viewGenerator.updateView(view, context) },
299+
factory = { context -> viewSuggestionsGenerator.populateView(context) },
300+
update = { view -> viewSuggestionsGenerator.updateView(view, context) },
226301
)
227302
}
228303
}
229304

305+
@Composable
306+
fun SearchContentUI(
307+
layout: SearchSuggestionsViewOptions.Layout,
308+
viewContentGenerator: SearchContentViewGenerator?,
309+
searchContentBlockNumber: Int,
310+
) {
311+
viewContentGenerator?.let { viewContentGenerator ->
312+
viewContentGenerator.getSearchContentViewOptions().setLayout(layout)
313+
var context = LocalContext.current
314+
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
315+
for (index in 0..searchContentBlockNumber - 1) {
316+
Row {
317+
AndroidView(
318+
factory = { context -> viewContentGenerator.populateView(context, index) },
319+
update = { view -> viewContentGenerator.updateView(view, context) },
320+
)
321+
}
322+
}
323+
}
324+
}
325+
}
326+
230327
@Preview(showBackground = true)
231328
@Composable
232329
fun SearchSuggestionsPreview() {

compose/app/src/main/java/com/google/samples/quickstart/searchinapps/compose/SearchInAppsViewModel.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,35 @@
1515
package com.google.samples.quickstart.searchinapps.compose
1616

1717
import androidx.lifecycle.ViewModel
18+
import com.google.android.libraries.searchinapps.SearchContentViewGenerator
1819
import com.google.android.libraries.searchinapps.SearchSuggestionsViewGenerator
1920
import com.google.android.libraries.searchinapps.SearchSuggestionsViewOptions
2021
import kotlinx.coroutines.flow.MutableStateFlow
2122
import kotlinx.coroutines.flow.StateFlow
22-
import kotlinx.coroutines.flow.update
2323
import kotlinx.coroutines.flow.asStateFlow
24+
import kotlinx.coroutines.flow.update
2425

2526
/** The ViewModel for the Jetpack Compose sample activity to store the data. */
2627
class SearchInAppsViewModel : ViewModel() {
27-
private val searchSuggestionsViewGenerator = MutableStateFlow<SearchSuggestionsViewGenerator?>(null)
28-
private val layout = MutableStateFlow<SearchSuggestionsViewOptions.Layout>(SearchSuggestionsViewOptions.Layout.COMPACT_CAROUSEL)
28+
private val searchContentViewGenerator = MutableStateFlow<SearchContentViewGenerator?>(null)
29+
private val searchSuggestionsViewGenerator =
30+
MutableStateFlow<SearchSuggestionsViewGenerator?>(null)
31+
private val layout =
32+
MutableStateFlow<SearchSuggestionsViewOptions.Layout>(
33+
SearchSuggestionsViewOptions.Layout.COMPACT_CAROUSEL
34+
)
35+
36+
public fun setSearchContentViewGenerator(searchContentViewGenerator: SearchContentViewGenerator) {
37+
this.searchContentViewGenerator.value = searchContentViewGenerator
38+
}
39+
40+
public fun getSearchContentViewGenerator(): StateFlow<SearchContentViewGenerator?> {
41+
return this.searchContentViewGenerator.asStateFlow()
42+
}
2943

3044
public fun setSearchSuggestionsViewGenerator(
31-
searchSuggestionsViewGenerator: SearchSuggestionsViewGenerator) {
45+
searchSuggestionsViewGenerator: SearchSuggestionsViewGenerator
46+
) {
3247
this.searchSuggestionsViewGenerator.value = searchSuggestionsViewGenerator
3348
}
3449

@@ -41,6 +56,6 @@ class SearchInAppsViewModel : ViewModel() {
4156
}
4257

4358
public fun updateLayout(layout: SearchSuggestionsViewOptions.Layout) {
44-
this.layout.update {layout}
59+
this.layout.update { layout }
4560
}
4661
}

compose/app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
<string name="search_text" translatable="false">Get suggestions</string>
1919
<string name="search_hint" translatable="false">Enter search context</string>
2020
<string name="location_hint" translatable="false">Enter location latitude, longitude and radius</string>
21+
<string name="search_repeat_hint" translatable="false">Enter search repeat</string>
2122
<string name="trending_text" translatable="false">Get trendings</string>
23+
<string name="search_content" translatable="false">Get content</string>
24+
<string name="load_more_content" translatable="false">More content</string>
2225
<string name="compact_carousel_layout" translatable="false">Compact Carousel</string>
2326
<string name="carousel_layout" translatable="false">Carousel</string>
2427
<string name="tiling_layout" translatable="false">Tiling</string>
-19.8 KB
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Uncomment the next line to define a global platform for your project
2+
# platform :ios, '9.0'
3+
4+
target 'SearchApertureSwiftUISample' do
5+
# Comment the next line if you don't want to use dynamic frameworks
6+
use_frameworks!
7+
8+
# Pods for SearchApertureSwiftUISample
9+
pod "Google-SearchInApps-SDK"
10+
11+
end

0 commit comments

Comments
 (0)