xccjk / x-blog

学习笔记
18 stars 2 forks source link

react native #90

Open xccjk opened 1 year ago

xccjk commented 1 year ago

报错 Invalid Podfile file: [!] Specifying multiple post_install hooks is unsupported..

post_install do |installer|
    flipper_post_install(installer)
  end
end

post_install do |pi|
  pi.pods_project.targets.each do |t|
    t.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
    end
  end
end

修改后

post_install do |pi|
  flipper_post_install(installer)
  pi.pods_project.targets.each do |t|
    t.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
    end
  end
end
xccjk commented 1 year ago

报错 Error installing Flipper

image

网络原因导致的报错

issue

xccjk commented 1 year ago

react native ui框架

https://github.com/rilyu/teaset

xccjk commented 1 year ago

react-native 代码修改未生效

使用react-native时,经常会出现调试模式下,修改js代码,然后依然运行旧代码的问题。这个时候禁用调试窗口的cache即可。

具体就在NetWork里,勾选Disable cache。

2021060915193550

xccjk commented 1 year ago

react native onLongPress方法在模拟器上失效

在启用了React Native Debugger的真实设备上进行测试后,这种情况会随机发生。禁用React Native Debugger将使您的问题消失

xccjk commented 1 year ago

react native setInterval 在真机模拟器上执行不正确

在启用了React Native Debugger的真实设备上进行测试后,setInterval执行不正确。禁用React Native Debugger将使您的问题消失

xccjk commented 8 months ago

react native中集成阿里云推送

安装依赖

pnpm install aliyun-react-native-push

Android配置

android/app/src/main/AndroidManifest.xml

<!-- 阿里云推送 -->
<meta-data
    android:name="com.alibaba.app.appkey"
    android:value="${ALIPUSH_APPKEY}" />
<meta-data
    android:name="com.alibaba.app.appsecret"
    android:value="${ALIPUSH_APPSECRET}" />

<receiver android:name="com.aliyun.ams.push.AliyunPushMessageReceiver" android:exported="false">
    <intent-filter>
        <action android:name="com.alibaba.push2.action.NOTIFICATION_OPENED" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.alibaba.push2.action.NOTIFICATION_REMOVED" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.alibaba.sdk.android.push.RECEIVE" />
    </intent-filter>
</receiver>

android/settings.gradle

include ':aliyun-react-native-push'
project(':aliyun-react-native-push').projectDir = new File(rootProject.projectDir, '.../node_modules/aliyun-react-native-push/android')

android/settings.gradle

// 配置HMS Core SDK的Maven仓地址。
maven {
  url 'https://developer.huawei.com/repo/'
}

android/app/build.gradle

defaultConfig {
    ...
    manifestPlaceholders = [
        ...
        ALIPUSH_APPKEY    : "xxx",
        ALIPUSH_APPSECRET : "xxx",
    ]
   ...
}

iOS配置

#import <CloudPushSDK/CloudPushSDK.h>
#import <AliyunReactNativePush.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...

  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

  // 设置代理,必须写代理,不然无法监听通知的接收与点击事件
  center.delegate = self;

  // 判断是否已申请通知权限
  [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
      if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined ||
          settings.authorizationStatus == UNAuthorizationStatusDenied) {
          // 申请通知权限
          [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge |
                                                   UNAuthorizationOptionSound |
                                                   UNAuthorizationOptionAlert )
                                completionHandler:^(BOOL granted, NSError * _Nullable error) {
              if (!error && granted) {
                  // 用户点击允许
                  NSLog(@"注册成功");
              } else {
                  // 用户点击不允许
                  NSLog(@"注册失败");
              }
          }];
      }
  }];

  // 判断是否已注册远程推送
  if (application.isRegisteredForRemoteNotifications == NO) {
      // 注册远程推送,获取 device token
      [application registerForRemoteNotifications];
  }

  ...

  return YES;
}

//注册 APNS 成功并上报 DeviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

  NSString *tokenStr = [[[[deviceToken description] stringByReplacingOccurrencesOfString: @"<" withString: @""]
                         stringByReplacingOccurrencesOfString: @">" withString: @""]
                        stringByReplacingOccurrencesOfString: @" " withString: @""];
  self.device_token = tokenStr;
  [AliyunPush didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

/*
 * APNs注册失败回调
 */
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  [AliyunPush didFailToRegisterForRemoteNotificationsWithError:error];
}

#pragma mark Notification Open
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo {
  [AliyunPush didReceiveRemoteNotification:userInfo];
}
//iOS 7 APNS
- (void)application:(UIApplication *)application didReceiveRemoteNotification:  (NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // iOS 10 以下 Required
  NSLog(@"iOS 7 APNS");
  [AliyunPush didReceiveRemoteNotifiaction:userInfo fetchCompletionHandler:completionHandler];
  completionHandler(UIBackgroundFetchResultNewData);
}

//ios 4 本地通知 todo
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
  NSDictionary *userInfo =  notification.userInfo;
  NSLog(@"iOS 4 本地通知");
  //  [[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_EVENT object:userInfo];
}

- (void)handleiOS10Notification:(UNNotification *)notification {
    UNNotificationRequest *request = notification.request;
    UNNotificationContent *content = request.content;
    NSDictionary *userInfo = content.userInfo;
    // 通知时间
    NSDate *noticeDate = notification.date;
    // 标题
    NSString *title = content.title;
    // 副标题
    NSString *subtitle = content.subtitle;
    // 内容
    NSString *body = content.body;
    // 角标
    int badge = [content.badge intValue];
    // 取得通知自定义字段内容,例:获取key为"Extras"的内容
    NSString *extras = [userInfo valueForKey:@"Extras"];
    // 通知打开回执上报
    [CloudPushSDK handleReceiveRemoteNotification:userInfo];
    NSLog(@"Notification, date: %@, title: %@, subtitle: %@, body: %@, badge: %d, extras: %@.", noticeDate, title, subtitle, body, badge, extras);
}

//iOS 10 前台收到消息
- (void)userNotificationCenter:(UNUserNotificationCenter *)center  willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
  NSDictionary * userInfo = notification.request.content.userInfo;
  if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    // Apns
    NSLog(@"iOS 10 APNS 前台收到消息");

    // 处理iOS 10通知相关字段信息
    [self handleiOS10Notification:notification];
    [AliyunPush userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];
    completionHandler(UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionSound);
  }
  else {
    // 本地通知 todo
    NSLog(@"iOS 10 本地通知 前台收到消息");
    //    [[NSNotificationCenter defaultCenter] postNotificationName:J_LOCAL_NOTIFICATION_EVENT object:userInfo];
  }
  //需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
  completionHandler(UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionSound);
}

//iOS 10 消息事件回调
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler: (void (^)(void))completionHandler {
  NSDictionary * userInfo = response.notification.request.content.userInfo;
  if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    NSLog(@"iOS 10 APNS 消息事件回调");
    [AliyunPush userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
  }
  else {
    // 本地通知 todo
    NSLog(@"iOS 10 本地通知 消息事件回调");
  }
  // 系统要求执行这个方法
  completionHandler();
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
  //重置个推角标
  if (application.applicationIconBadgeNumber > 0) {  //badge number 不为0,说明程序有个推图标
    //如果需要角标清空需要调用系统方法设置
    [application setApplicationIconBadgeNumber: 0];   //将图标清零。
  }
}

使用

alipush.ts

// 阿里云推送通知
import * as AliyunPush from 'aliyun-react-native-push';
import { Platform } from 'react-native';

import { isJson } from '../utils/math';

const IMPORTANCE_DEFAULT = 3;

const channel = [
  { id: 'xxx', name: 'xx', importance: IMPORTANCE_DEFAULT, desc: 'xxx' },
];

const CONFIG_ENV: any = {
  'dev': { appKey: 'xxx', appSecret: 'xxx' },
  'test': { appKey: 'xxx', appSecret: 'xxx' },
};

export class AliyunPushManager {
  /**
   * @description 单例对象
   */
  private static instance = new AliyunPushManager();
  // 禁止外部调用
  private constructor() {
    this.pushInitial();
  }
  /**
   * @description 获取alipush管理对象
   */
  static getInstance(): AliyunPushManager {
    return AliyunPushManager.instance;
  }

  pushInitial(): void {
    if (Platform.OS == 'ios') {
      // 系统静音不播放
    } else {
    }
  }

  // 接收自定义消息
  addReceiveCustomMsgListener(callback: (message: Object) => void): void {
    AliyunPush.addMessageCallback((message: any) => {
      console.log('自定义消息', message);
      if (message) {
        if (Platform.OS === 'android') {
          let { content } = message || {};
          let result = isJson(content) ? JSON.parse(content) : {};
          callback(result);
        } else {
          let { body } = message || {};
          let result = isJson(body) ? JSON.parse(body) : {};
          callback(result);
        }
      }
    });
  }

  // 移除自定义消息
  removeMsgListener(callback: (message: Object) => void): void {
    AliyunPush.addNotificationRemovedCallback(callback);
  }

  // 推送通知回调
  addNotificationListener(callback: any): void {
    AliyunPush.addNotificationRemovedCallback(callback);
    AliyunPush.addNotificationCallback(callback);
  }

  // 通知栏打开通知扩展处理
  addNotificationOpenedCallback(callback: any): void {
    AliyunPush.addNotificationRemovedCallback(callback);
    AliyunPush.addNotificationOpenedCallback(callback);
  }

  // 设置日志
  async setLog() {
    const enable = true;
    if (enable) {
      if (Platform.OS === 'ios') {
        await AliyunPush.turnOnIOSDebug();
        console.log('push-打开ios Debug日志成功');
      } else {
        await AliyunPush.setAndroidLogLevel(2);
        console.log('push-打开android Debug日志成功');
      }
    }
  }

  // 初始化
  async init(callback) {
    if (Platform.OS === 'ios') {
      const { appKey, appSecret } = CONFIG_ENV.dev || {};
      const { code, errorMsg } = await AliyunPush.initPush(appKey, appSecret);
      if (code === AliyunPush.kAliyunPushSuccessCode) {
        console.log('push-initPush: 初始化iOS AliyunPush成功');
        callback && callback();
      } else {
        console.log(`push-initPush: iOS AliyunPush 初始化失败,errorMsg: ${errorMsg?.toString()}`);
      }
    } else {
      const res = await AliyunPush.initPush();
      if (res.code === AliyunPush.kAliyunPushSuccessCode) {
        console.log('push-init: 初始化Android AliyunPush成功');
        callback && callback();
      } else {
        let errorMsg = res.errorMsg?.toString();
        console.log(`push-init: Android AliyunPush 初始化失败,errorMsg: ${errorMsg}`);
      };
    }
  }

  // 开始初始化
  loadJs(callback?: any) {
    AliyunPushManager.getInstance().setLog();
    AliyunPushManager.getInstance().init(callback);
    AliyunPushManager.getInstance().setChannel();
    if (Platform.OS === 'ios') {
      AliyunPushManager.getInstance().getApnsDeviceToken();
      AliyunPushManager.getInstance().isIOSChannelOpened();
    }
  }

  // 设置别名
  async setAlias(alias: [string]) {
    await AliyunPushManager.getInstance().removeAlias();
    let CryptoJS = require('crypto-js');
    let signStrs: any[] = [];
    alias.map(async (key: string) => {
      let signStr = CryptoJS.MD5(key).toString();
      signStrs.push(signStr);
      const { code, errorMsg } = await AliyunPush.addAlias(signStr);
      if (code === AliyunPush.kAliyunPushSuccessCode) {
        console.log('push-setAlias: 添加别名成功')
      } else {
        console.log(`push-setAlias: 添加别名失败, error: ${errorMsg?.toString()}`);
      };
    });
    console.log('push-alias', alias, signStrs);
  }

  // 查询别名
  async listAlias() {
    const res: any = await AliyunPush.listAlias();
    console.log('push-listAlias', res);
    const { code, aliasList } = res;
    if (code === AliyunPush.kAliyunPushSuccessCode) {
      return aliasList ? aliasList.split(',') : [];
    }
    return [];
  }

  // 删除别名
  async removeAlias(callback?: any) {
    const alias = await AliyunPushManager.getInstance().listAlias();
    if (alias.length) {
      const res = await Promise.all(alias.map((key: string) => {
        return AliyunPush.removeAlias(key);
      }));
      if (res.filter(item => item.code === AliyunPush.kAliyunPushSuccessCode).length === res.length) {
        console.log('push-removeAlias: 删除别名成功');
        callback && callback();
      } else {
        console.log(`push-removeAlias: 删除别名失败`);
      }
    }
  }

  // 获取设置ID
  async getDeviceId() {
    const deviceId = await AliyunPush.getDeviceId();
    if (deviceId === null) {
      console.log(`push-getDeviceId: deviceId为空,请先初始化AliyunPush`);
    } else {
      console.log(`push-getDeviceId: ${deviceId}`)
    }
  }

  // 设置渠道编号
  async createAndroidChannel(params: { id: string, name: string, importance: number, desc: string }) {
    if (Platform.OS === 'ios') {

    } else {
      const { code, errorMsg } = await AliyunPush.createAndroidChannel(params);
      if (code === AliyunPush.kAliyunPushSuccessCode) {
        console.log(`push-createAndroidChannel: 创建通道成功`);
      } else {
        console.log(`push-createAndroidChannel: 创建通道失败, error: ${errorMsg}`);
      }
    }
  }

  // 设置渠道list
  setChannel() {
    // 设置渠道编号
    channel.map(params => {
      AliyunPushManager.getInstance().createAndroidChannel(params);
    });
  }

  // ios 通知通道是否打开
  async isIOSChannelOpened() {
    const opened = await AliyunPush.isIOSChannelOpened();
    if (opened) {
      console.log('push-ios: 通道已打开');
    } else {
      console.log('push-ios: 通道未打开');
    }
  }

  // ios 获取APNs Token
  async getApnsDeviceToken() {
    const token = await AliyunPush.getApnsDeviceToken();
    console.log('push-token', token);
  }

  // 移除所有回调
  removePushCallback() {
    AliyunPush.removePushCallback()
  }
}
import { AliyunPushManager } from './alipush';

AliyunPushManager.getInstance().loadJs();
xccjk commented 5 months ago

fastlane 安装慢

不要使用下面这种方法安装,看不到进度,特别慢

sudo gem install -n /usr/local/bin fastlane -NV

解决方案:

ruby版本要求2.7+,通过rvm来安装多版本ruby版本

创建一个 Gemfile 文件,内容如下:

source "https://gems.ruby-china.com/"

gem "fastlane"

使用 Bundler 安装 Fastlane:

bundle install

验证 Fastlane 是否正确安装:

bundle exec fastlane --version
xccjk commented 5 months ago

rvm安装多版本ruby

查看当前版本:

ruby -v

查看可按照版本:

rvm list known

安装指定版本:

rvm install ruby-3.2.1

上面这样安装应该会报错,修改为下面命令:

rvm install ruby-3.2.1 --with-openssl-dir=`brew --prefix openssl`

设置默认版本:

rvm use 3.2.1 --default

参考

xccjk commented 3 weeks ago

react-navigation StackActions实现跳转页面,重置页面栈

const pushAction = StackActions.push('Home', {})
navigation.dispatch(pushAction)
xccjk commented 3 weeks ago

react-navigation 自定义侧边栏

Drawer.Navigator
      drawerContent={(props) => <CustomDrawerContent {...props} />}
      screenOptions={drawerScreenOptions}
      initialRouteName="Home">
      <Drawer.Screen name="Home" component={HomeScreen} />
      ...
    </Drawer.Navigator>

CustomDrawerContent.tsx

import React, { useState, useEffect, useCallback } from 'react'
import { DrawerContentScrollView } from '@react-navigation/drawer'

const CustomDrawerContent = React.memo((props) => {
  return (
    <DrawerContentScrollView {...props}>
      ...
    </DrawerContentScrollView>
  )
})

export default CustomDrawerContent
xccjk commented 3 weeks ago

react native键盘弹出时,点击列表收起键盘并且选中列表项

对于FlatList和ScrollView组件,添加disableScrollViewPanResponder属性

<FlatList
  ...
  disableScrollViewPanResponder={true}
/>