2023年8月29日 星期二

[iOS][Swift][App] 實作搜尋建議

Photo by Ketut Subiyanto

簡單記錄一下實作搜尋建議的方法,完整的程式在下方

struct ContentView: View {
    @State private var searchText = ""
    @State private var selectedSuggestion = ""
    // 建議列表
    @State private var suggestions: [String] = ["Apple 蘋果", "ALLSAINTS", "BOTTEGA VENETA", "COSME DECORTE 黛珂", "Nike 耐吉", "Dell 戴爾", "COS", "Zara", "Emilie Louis", "L.ERICKSON", "SPRAYGROUND", "gubami Social-法式tapas餐廳", "Sarabeth's"]
    @State private var showSuggestions = false
    
    var body: some View {
        VStack {
	    // 搜尋欄位
            TextField("Search", text: $searchText)
                .padding(.horizontal, 15)
                .padding(.vertical, 10)
                .background(Color(.systemGray6))
                .cornerRadius(8)
                .padding(.top, 10)
                .padding(.bottom, 5)
                .onChange(of: searchText) { newValue in
                    showSuggestions = !newValue.isEmpty
                }
            
            // 選擇搜尋建議後的顯示
            if !selectedSuggestion.isEmpty {
                Text("Selected: \(selectedSuggestion)")
                    .padding(.top, 10)
            }
                        
            if showSuggestions {
                List {
                    ForEach(filteredSuggestions, id: \.self) { suggestion in
                        Text(suggestion)
                            .onTapGesture {
                                selectedSuggestion = suggestion
                                searchText = ""  // 清空 TextField
                                showSuggestions = false  // 隱藏建議列表
                            }
                    }
                    if filteredSuggestions.isEmpty {
                        Text("找不到品牌")
                            .foregroundColor(.gray)
                    }
                }
                .background(Color.white)
                .cornerRadius(8)
                .shadow(radius: 5)
                .padding()
            }
            Spacer()  // 添加一個間距,以便頁面內容和建議列表不重疊
        }
        .padding()
        
        var filteredSuggestions: [String] {
            if searchText.isEmpty {
                return []
            }
            return suggestions.filter({ $0.localizedCaseInsensitiveContains(searchText) })
        }
    }
}

2023年8月26日 星期六

[iOS][Swift][App] 整合 Google AdMob 到 iOS App

Photo by Ketut Subiyanto

我在整合 Google AdMob 時卡了超久,Google 了也沒找到很直接能解決的方法,想說在此做個記錄,讓以後的我能照著做,也讓遇到類似問題的人能夠有個解法,以下是參考 官方說明 做的

第一動,Import the Mobile Ads SDK

先在 xocde project 的根目錄下(.xcodeproj 檔案的路徑)執行 pod init,這樣就能產生一個 Podfile 檔案,若沒安裝 cocopods 可以 follow 這裡 安裝,然後再按照 這裡 的做法,加

pod 'Google-Mobile-Ads-SDK'

在 Podfile 檔案,然後執行下面,記得此時要將 xcode 關閉

pod install --repo-update

這邊我遇到一個問題

[!] Unable to determine the platform for the `your project name` target.

解決方法是將 Podfile 檔案裡的第二行 uncomment 就可以了,完成後如下


platform :ios, '9.0'


第二動,Update your Info.plist

遇到的第一個問題是,我找不到 Info.plist 檔案

參考 這邊,原來 info.plist 變成了 project 設定裡的 tab

然後將 GADApplicationIdentifier (1個) 和 SKAdNetworkItems (49個) 輸入(如下圖紅框)


第三動,建立 banner structure 來呼叫顯示廣告
import GoogleMobileAds
struct BannerVC: UIViewControllerRepresentable {
    var bannerID: String
    var width: CGFloat

    func makeUIViewController(context: Context) -> UIViewController {
        let view = GADBannerView(adSize: GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(width))

        let viewController = UIViewController()
        view.adUnitID = bannerID
        
        view.rootViewController = viewController
        viewController.view.addSubview(view)

#if false
        /* Simulator */
        let request = GADRequest()
        let extras = GADExtras()
        extras.additionalParameters = ["suppress_test_label": "1"]
        request.register(extras)
        view.load(request)
#else
        /* Real device */
        view.load(GADRequest())
#endif
        
        return viewController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

struct Banner: View {
    var bannerID: String
    var width: CGFloat

    var size: CGSize {
        return GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(width).size
    }

    var body: some View {
        BannerVC(bannerID: bannerID, width: width)
            .frame(width: size.width, height: size.height)
    }
}
struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
        }
        .padding()
        Banner(bannerID: "ca-app-pub-3940256099942544/2934735716", width: UIScreen.main.bounds.width)
    }
} 

實作方式如上,這邊用的 bannerID 是測試使用的,請參考這邊,順利的話就可以看到下面的畫面

Simulator

若不想在 Simulator 上看到 "Test mode" 的字樣,將上面程式的 /* Simulator */ 上的 if false 改成 if true,就可將之移除如下圖,這功能在你上架 app 提供截圖時會用到
若是跑在實機上的話,上述的程式記得改成 if false,會看到如下畫面
Note

若想 build 在 Mac 上會遇到 No such module 'GoogleMobileAds' 的 error,這個問題我也想知道解答,歡迎提供給我,謝謝

環境

  • Mac Mini M1
  • Xcode Version 14.3 (14E222b)
  • iPhone 12 Pro Max (16.6)

Reference

  • COCOAPODS getting-start (link)
  • Mobile Ads SDK (iOS) Get Started (link)